之前也講過,Python 沒有真正意義上的私有屬性。然後這就導致了 Python 類別的封裝性比較差。我們有時會希望 Python 能夠定義私有屬性,然後提供公共可存取的 get 方法和 set 方法。 Python 其實可以透過魔術方法來實現封裝。
方法 | 說明 |
#__getattr__(self, name) | 此方法定義了你試圖存取一個不存在的屬性時的行為。因此,重載該方法可以實現捕獲錯誤拼寫然後進行重定向, 或對一些廢棄的屬性進行警告。 |
__setattr__(self, name, value) | 定義了對屬性進行賦值和修改操作時的行為。不管物件的某個屬性是否存在,都允許為該屬性進行賦值.有一點需要注意,實現__setattr__ 時要避免"無限遞歸"的錯誤, |
__delattr__(self , name) | __delattr__ 與__setattr__ 很像,只是它定義的是你刪除屬性時的行為。實作__delattr__ 是同時要避免"無限遞迴"的錯誤 |
__getattribute__(self, name) | __getattribute__ 定義了你的屬性被存取時的行為,相比較,__getattr__ 只有該屬性不存在時才會起作用。因此,在支援 __getattribute__ 的 Python 版本,呼叫__getattr__ 前必定會呼叫 __getattribute__``__getattribute__ 同樣要避免"無限遞歸"的錯誤。 |
透過上面的方法表可以知道,在進行屬性存取控制定義的時候你可能會很容易的引起一個錯誤,可以看看下面的範例:
def __setattr__(self, name, value): self.name = value # 每当属性被赋值的时候, ``__setattr__()`` 会被调用,这样就造成了递归调用。 # 这意味这会调用 ``self.__setattr__('name', value)`` ,每次方法会调用自己。这样会造成程序崩溃。 def __setattr__(self, name, value): # 给类中的属性名分配值 self.__dict__[name] = value # 定制特有属性
上面方法的呼叫具體範例如下:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class User(object): def __getattr__(self, name): print('调用了 __getattr__ 方法') return super(User, self).__getattr__(name) def __setattr__(self, name, value): print('调用了 __setattr__ 方法') return super(User, self).__setattr__(name, value) def __delattr__(self, name): print('调用了 __delattr__ 方法') return super(User, self).__delattr__(name) def __getattribute__(self, name): print('调用了 __getattribute__ 方法') return super(User, self).__getattribute__(name) if __name__ == '__main__': user = User() # 设置属性值,会调用 __setattr__ user.attr1 = True # 属性存在,只有__getattribute__调用 user.attr1 try: # 属性不存在, 先调用__getattribute__, 后调用__getattr__ user.attr2 except AttributeError: pass # __delattr__调用 del user.attr1
輸出的結果:
调用了 __setattr__ 方法 调用了 __getattribute__ 方法 调用了 __getattribute__ 方法 调用了 __getattr__ 方法 调用了 __delattr__ 方法下一節