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