零基礎入門學習Python(23):魔法方法(3)屬性訪問
在講解今天的內容之前,我們先重寫兩個函數__str__()和__repr__()
,第一個函數表示可以使用print()打印對象的值,第二個函數表示直接寫出對象名就可以打印出對象的值。
>>> class Test:
def __str__(self):
return "Hello everyone."
>>> t1 = Test()
>>> t1 #直接寫出t1得到它在內存中的位置
<__main__.Test object at 0x028859F0>
>>> print(t1) #需要調用print()才能打印出對象的值
Hello everyone.
>>> class Test:
def __repr__(self):
return "Hello everyone"
>>> t2 = Test() #重寫__repr__()之後寫出t2,則可以直接得到對象的值
>>> t2
Hello everyone
下面介紹一下Python屬性訪問的魔法方法:
1)__getattr__(self,name)
:定義當用戶試圖獲取一個不存在的屬性時的行爲;
2)__getattribute__(self,name)
:定義當該類的屬性被訪問時的行爲;
3)__setattr__(self,name,value)
:定義當一個屬性被設置時的行爲;
4)__delattr__(self,name)
:定義當一個屬性被刪除時的行爲;
在訪問屬性的方法調用的時候,會先調用__getattribute__(self,name)
方法,當屬性不存在時再調用__getattr__(self,name)
方法,下面通過舉例驗證一下。
>>> class TestAttr:
def __getattribute__(self,name): #分別重寫屬性訪問的魔法方法
print('getattribute...')
return super().__getattribute__(name) #返回值調用沒重寫時候的方法
def __getattr__(self,name):
print('getattr...')
def __setattr__(self,name,value):
print('setattr...')
super().__setattr__(name,value)
def __delattr__(self, name):
print('delattr...')
super().__delattr__(name)
>>> a1 = TestAttr()
>>> a1.x #x屬性不存在,則先調用__getattribute__()方法,再調用__getattr__()方法
getattribute...
getattr...
>>> a1.x = 2 #設置對象的x屬性
setattr...
>>> a1.x #再次訪問x時,則直接調用__getattribute__()方法並顯示出x的值
getattribute...
2
>>> del a1.x #刪除對象的x屬性
delattr...
最後舉一個例子:寫一個矩形類,要求長寬默認爲0,如果爲一個叫square的屬性賦值,說明是一個正方形,則長寬都等於square,最後計算矩形的面積。
>>> class Rectangle:
def __init__(self, length = 0, width = 0):
self.length = length #賦值操作,會進到__setattr__()方法中
self.width = width
def __setattr__(self, name, value): #重寫__setattr__()方法
if name == "square": #先判斷是否爲正方形
self.length = value
self.width = value
else: #如果不是,則調用未重寫時候設置屬性的方法
super().__setattr__(name, value)
def getArea(self):
return self.length * self.width
>>> r1 = Rectangle(2,3) #初始化長寬
>>> r1.getArea()
6
>>> r1.length = 5 #可以只改變長或寬的值
>>> r1.getArea()
15
>>> r1.square = 7 #給square賦值時,長寬相等
>>> r1.length
7
>>> r1.width
7
>>> r1.getArea()
49
>>> r1.__dict__ #顯示對象r1的屬性
{'width': 7, 'length': 7}
由於對象的屬性組成了一個字典類型的對象,所以設置屬性時,除了可以使用super()方法之外,還可以利用字典的鍵值對給屬性賦值,即super().__setattr__(name, value)
這行代碼可以改爲self.__dict__[name] = value
。當然,推薦大家使用super()方法。