2017-04-14 67 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中,它在技術上是「可選的」,但它會產生一個「舊式類」,它不能正確地處理屬性(以及一般的描述符),所以在這種情況下它不是可選的。 –