国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

實例講解Python編程中@property裝飾器的用法

2019-11-25 16:42:53
字體:
來源:轉載
供稿:網友

取值和賦值

class Actress():  def __init__(self):    self.name = 'TianXin'    self.age = 5


類Actress中有兩個成員變量name和age。在外部對類的成員變量的操作,主要包括取值和賦值。簡單的取值操作是x=object.var,簡單的賦值操作是object.var=value。

>>> actress = Actress()>>> actress.name  #取值操作'TianXin'>>> actress.age    #取值操作20>>> actress.name = 'NoName'   #賦值操作>>> actress.name'NoName'

使用 Getter 和 Setter
上述簡單的取值和賦值操作,在某些情況下是不能滿足要求的。比如,如果要限制Actress的年齡范圍,那么只使用上述簡單的賦值操作就不能滿足要求了。getter和setter實現這樣的要求。

class Actress():  def __init__(self):    self._name = 'TianXin'    self._age = 20  def getAge(self):    return self._age  def setAge(self, age):    if age > 30:      raise ValueError    self._age = age

調用setAge函數可以實現將變量_age的取值范圍限制到小于30.

>>> actress = Actress()>>> actress.setAge(28)>>> actress.getAge()28>>> actress.setAge(35)ValueError

使用property
property的定義是:
其中,fget是取值函數,fset是賦值函數,fdel是刪除函數。使用property也實現上述對成員變量的取值限制。

class Actress():  def __init__(self):    self._name = 'TianXin'    self._age = 20  def getAge(self):    return self._age  def setAge(self, age):    if age > 30:      raise ValueError    self._age = age   age=property(getAge, setAge, None, 'age property')

經過上面的定義后,可以像簡單取值和賦值操作一樣操作age。比如,

>>> actress = Actress()>>> actress.age20>>> actress.age = 18>>> actress.age = 55ValueError

使用@property
使用@property同樣可以實現上述類的定義。

class Actress():  def __init__(self):    self._name = 'TianXin'    self._age = 20  @property  def age(self):    return self._age  @age.setter  def age(self, age):    if age > 30:      raise ValueError    self._age = age

使用時的示例:

>>> actress = Actress()>>> actress.age20>>> actress.age = 18>>> actress.age = 45ValueError

Python2 和 Python3中使用property的區別
上述property示例在Python3的環境下有效。在Python2中,使用property時,類定義時需要繼承object。否則,property的賦值操作不可使用。

Python2下property的正確使用方式:

class Actress(object):      #差別在這里  def __init__(self):    self._name = 'TianXin'    self._age = 20  @property  def age(self):    return self._age  @age.setter  def age(self, age):    if age > 30:      raise ValueError    self._age = age   def setName(self, name):    self._name = name  def getName(self):    return self._name  def delName(self):    print('Goodbye...')    del self._name  name = property(getName, setName, delName, 'name property')
實例:快速進行代碼重構
從前,Python程序員Alice要打算創建一個代表金錢的類。她的第一個實現形式大概是下面這樣:
# 以美元為基礎貨幣的Money類的首個版本class Money:  def __init__(self, dollars, cents):    self.dollars = dollars    self.cents = cents    # 還有其他一些方法,我們暫時不必理會

這個類后來被打包到一個Python庫里,并且慢慢地被許多不同的應用使用。舉個例子,另一個團隊中的Python程序員Bob是這樣使用Money類的:

money = Money(27, 12)message = "I have {:d} dollars and {:d} cents."print(message.format(money.dollars, money.cents))# "I have 27 dollars and 12 cents."money.dollars += 2money.cents += 20print(message.format(money.dollars, money.cents))# "I have 29 dollars and 32 cents."

這樣使用并沒有錯,但是卻出現了代碼可維護性的問題。你發現了嗎?

幾個月或是幾年之后。Alice想要重構Money類的內部實現,不再記錄美元和美分,而是僅僅記錄美分,因為這樣做可以讓某些操作簡單很多。下面是她很可能會作的修改:

# Money類的第二個版本class Money:  def __init__(self, dollars, cents):    self.total_cents = dollars * 100 + cents

這一修改帶來一個后果:引用Money類的每一行代碼都必須要調整。有時候很幸運,你就是所有這些代碼的維護者,只需要自己直接重構即可。但是Alice的情況就沒有這么好了;許多團隊都復用了她的代碼。因此,她需要協調他們的代碼庫與自己的修改保持一致,也許甚至要經歷一段特別痛苦、漫長的正式棄用過程(deprecation process)。

幸運的是,Alice知道一種更好的解決辦法,可以避免這個令人頭疼的局面出現:使用Python內建的property裝飾器。@property一般應用在Python方法上,可以有效地將屬性訪問(attribute access)變成方法調用(method call)。舉個例子,暫時將Money類拋至一邊,假設有一個代表人類的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)

代碼樣式不同,是因為之前用的工具出問題了。―EarlGrey

請注意full_name方法。除了在def語句上方裝飾了@property之外,該方法的聲明沒有什么不同的地方。但是,這卻改變了Person對象的運作方式:

>>> buddy = Person('Jonathan', 'Doe')>>> buddy.full_name'Jonathan Doe'

我們發現,盡管full_name被定義為一個方法,但卻可以通過變量屬性的方式訪問。在最后一行代碼中沒有()操作符;我并沒有調用full_name方法。我們所做的,可以說是創建了某種動態屬性。

回到本文中的Money類,Alice對它作了如下修改:

# 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

除了使用@property裝飾器定義了dollars屬性的getter外,Alice還利用@dollars.setter創建了一個setter。Alice還對cents`屬性作了類似處理。

那么現在,Bob的代碼要做哪些相應的修改呢?根本不用改!

# 他的代碼完全沒有變動,但是卻可以正常調用Money類。money = Money(27, 12)message = "I have {:d} dollars and {:d} cents."print(message.format(money.dollars, money.cents))# "I have 27 dollars and 12 cents."money.dollars += 2money.cents += 20print(message.format(money.dollars, money.cents))# "I have 29 dollars and 32 cents."# 代碼邏輯也沒有問題。money.cents += 112print(message.format(money.dollars, money.cents))# "I have 30 dollars and 44 cents."

事實上,所有使用了Money類的代碼都不需要進行修改。Bob不知道或根本不在乎Alice去除了類中的dollars和cents屬性:他的代碼還是和以前一樣正常執行。唯一修改過的代碼就是Money類本身。

正是由于Python中處理裝飾器的方式,你可以在類中自由使用簡單的屬性。如果你所寫的類改變了管理狀態的方法,你可以自信地通過@property裝飾器對這個類(且只有這個類)進行修改。這是一個共贏的方法!相反,在Java等語言中,程序員必須主動去定義訪問屬性的方法(例如getDollars或setCents)。

最后要提示大家:這種方法對于那些被其他程序員和團隊復用的代碼最為重要。假設僅僅是在你自己一個維護的應用中創建一個類似Money的類,那么如果你改變了Money的接口,你只需要重構自己的代碼就可以。這種情況下,你沒有必要像上面說的那樣使用@property裝飾器。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 柯坪县| 五大连池市| 宁乡县| 尉氏县| 哈尔滨市| 德令哈市| 临桂县| 竹山县| 上杭县| 华池县| 遂溪县| 佛教| 怀来县| 柳林县| 平原县| 庄浪县| 乌拉特中旗| 遂昌县| 东丰县| 翁牛特旗| 安西县| 涟源市| 通河县| 沧源| 东阿县| 乌恰县| 新昌县| 藁城市| 万全县| 温州市| 封丘县| 五家渠市| 枞阳县| 黑山县| 乌拉特前旗| 林州市| 漯河市| 东辽县| 张掖市| 焦作市| 永胜县|