從前,Python程序員Alice要打算創(chuàng)建一個(gè)代表金錢的類。她的第一個(gè)實(shí)現(xiàn)形式大概是下面這樣:
#以美元為基礎(chǔ)貨幣的Money類的首個(gè)版本
class Money:
? ? def __init__(self, dollars, cents):
? ? ? ? self.dollars = dollars
? ? ? ? self.cents = cents
? ? ? ? #還有其他一些方法,我們暫時(shí)不必理會(huì)
????????幾個(gè)月或是幾年之后。Alice想要重構(gòu)Money類的內(nèi)部實(shí)現(xiàn),不再記錄美元和美分,而是僅僅記錄美分,因?yàn)檫@樣做可以讓某些操作簡(jiǎn)單很多。下面是她很可能會(huì)作的修改:
#Money類的第二個(gè)版本
class Money:
? ? def __init__(self, dollars, cents):
? ? ? ? self.total_cents = dollars * 100 + cents
????????幸運(yùn)的是,Alice知道一種更好的解決辦法,可以避免這個(gè)令人頭疼的局面出現(xiàn):使用Python內(nèi)建的property裝飾器。@property一般應(yīng)用在Python方法上,可以有效地將屬性訪問(wèn)(attribute access)變成方法調(diào)用(method call)。舉個(gè)例子,暫時(shí)將Money類拋至一邊,假設(shè)有一個(gè)代表人類的Person類(class):
class Person:
? ? def __init__(self, first, last):? ? ? ? self.first = first
? ? ? ? self.last = last
? ? @property
? ? def full_name(self):
? ? ? ? return '{} {}'.format(self.first, self.last)
????????請(qǐng)注意full_name方法。除了在def語(yǔ)句上方裝飾了@property之外,該方法的聲明沒(méi)有什么不同的地方。但是,這卻改變了Person對(duì)象的運(yùn)作方式:
>>> buddy = Person('Jonathan', 'Doe')
>>> buddy.full_name
'Jonathan Doe'
????????我們發(fā)現(xiàn),盡管full_name被定義為一個(gè)方法,但卻可以通過(guò)變量屬性的方式訪問(wèn)。在最后一行代碼中沒(méi)有()操作符;我并沒(méi)有調(diào)用full_name方法。我們所做的,可以說(shuō)是創(chuàng)建了某種動(dòng)態(tài)屬性。
回到本文中的Money類,Alice對(duì)它作了如下修改:
# Money類的最終版本
class Money:
? ? def __init__(self, dollars, cents):? ? ? ??
????????????self.total_cents = dollars * 100 + cents
? ? # Getter and setter for dollars...
? ? @property
? ? def dollars(self):
? ? ? ? return self.total_cents // 100;
? ? @dollars.setter
? ? def dollars(self, new_dollars):? ? ? ??
????????????self.total_cents = 100 * new_dollars + self.cents
? ? ? # And the getter and setter for cents.
? ? @property
? ? def cents(self):
? ? ? ? return self.total_cents % 100;
? ? @cents.setter
? ? def cents(self, new_cents):? ? ? ??
????????????self.total_cents = 100 * self.dollars + new_cents