2017-04-14 64 views
0

我想允许用户在实例化后更改self.path,但不允许其他实例变量。但是,如果self.path被更改,则应重新评估其他实例变量。这可能吗?防止更改实例变量

class File(object): 

    def __init__(self, path): 
     self.path = os.path.abspath(path) 
     self.name = os.path.basename(self.path) 
     self.parent = os.path.dirname(self.path) 

     self.extension = self._get_extension() 
     self.category = self.get_category(self.extension) 
     self.exists = os.path.isfile(self.path) 

    def _get_extension(self): 
     extension = None 
     result = os.path.splitext(self.name)[1][1:] 
     if result: 
      extension = result 
     return extension 

    def get_category(self, extension): 
     if extension: 
      file_extension = extension.upper() 
      for key in fileGroups.keys(): 
       common = set(fileGroups[key]) & set([file_extension]) 
       if common: 
        return key 
     return 'UNDEFINED' 

回答

1

https://stackoverflow.com/a/598092/3110529你正在寻找的是属性getter/setter模式。 Python通过@property@member.setter实现了这一点,你可以在上面的答案的例子中看到这一点。

在你的问题而言,你可以这样做解决了下列文件:

class File(object): 

    def __init__(self, path): 
     self.__path = os.path.abspath(path) 
     self.__name = os.path.basename(self.path) 
     self.__parent = os.path.dirname(self.path) 

     self.__extension = self._get_extension() 
     self.__category = self.get_category(self.extension) 
     self.__exists = os.path.isfile(self.path) 

    @property 
    def path(self): 
     return self.__path 

    @path.setter 
    def path(self, value): 
     self.__path = value 
     # Update other variables here too 

    @property 
    def name(self): 
     return self.__name 

etc for the rest of your properties 

这意味着你可以做的东西,如:

file = File("a path") 
print(file.path) 
file.path = "some other path" 

# This will throw an AttributeError 
file.name = "another name" 

注意,一切正常相同,但性能没有制定者如果试图修改会抛出错误。

这确实会让您的File类显着变大,但由于没有实现setter,因此它可以防止用户更改path以外的成员。从技术上讲,用户仍然可以做file.__path = "something else",但通常理解的是,带有双下划线前缀的成员是私人的,不应该被篡改。

+0

谢谢,帮了很多。 – giantas

+0

但是,如何覆盖File的子类中的路径@property? (如果你不介意) – giantas

+0

@giantas这个答案应该可以帮助你http://stackoverflow.com/a/1021484/3110529下面的答案使用'超'http://stackoverflow.com/a/1021477/3110529 – Dillanm

1

Dilanm是对的。如果您需要使访问使用属性成员变量为只读或添加验证或其他任务。请注意,类声明中的(object)是可选的,并且由于没有办法在python类中强制实现私有成员,所以我只会强调我的意图是'_',除非您确实有'__'的理由。

#!/usr/bin/env python3 

import os.path 

class File: 
    def __init__(self, path): 
     self._path = path 
     self.compute_others() 

    def compute_others(self): 
     self._parent = os.path.dirname(self._path) 
     pass # add other attributes to be computed 

    # getter, also makes .path read-only 
    @property 
    def path(self): 
     return self._path 

    # setter, allows setting but adds validation or other tasks 
    @path.setter 
    def path(self, path): 
     self._path = path 
     self.compute_others() 

    # other attributes only have getters (read-only) 
    @property 
    def parent(self): 
     return self._parent 

    def __str__(self): 
     return 'path:{}\nparent:{}\n\n'.format(self.path, self.parent) 

f = File('/usr') 
print(f) 

f.path = '/usr/local' 
#f.parent = '/tmp' # error, read-only property 
print(f) 

要重写一个成员,只需在子类中再次定义它。属性没有什么不同。

+2

“请注意类声明中的(object)是可选的”:仅在Python 3.x中。在Python 2.x中,它在技术上是“可选的”,但它会产生一个“旧式类”,它不能正确地处理属性(以及一般的描述符),所以在这种情况下它不是可选的。 –