>

property装饰器的用法,飞快重构Python代码

- 编辑:www.bifa688.com -

property装饰器的用法,飞快重构Python代码

取值和赋值

实例疏解Python编制程序中@property装饰器的用法,[email protected]

取值和赋值

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.age
20
>>> actress.age = 18
>>> actress.age = 55

ValueError

使用@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.age
20
>>> actress.age = 18
>>> actress.age = 45
ValueError

Python2 和 Python3中使用property的区别 上述property示例在Python三的条件下有效。在Python第22中学,使用property时,类定义时索要承袭object。不然,property的赋值操作不可动用。

Python二下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工程师阿丽丝要准备创造一个表示金钱的类。她的首先个落到实处格局大意是上边那样:

# 以美元为基础货币的Money类的首个版本
class Money:
  def __init__(self, dollars, cents):
    self.dollars = dollars
    self.cents = cents
    # 还有其他一些方法,我们暂时不必理会

其一类新兴被打包到2个PythonCurry,并且逐步地被大多两样的利用使用。比如,另2个集体中的Python技术员鲍勃是那般使用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  = 2
money.cents  = 20
print(message.format(money.dollars, money.cents))
# "I have 29 dollars and 32 cents."

诸如此类使用并从未错,不过却现身了代码可维护性的主题素材。你发觉了吗?

多少个月大概几年之后。Iris想要重构Money类的中间贯彻,不再记录澳元和美分,而是只有记录美分,因为那样做能够让某个操作简捷大多。上边是她很大概会作的修改:

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

那1修改带来1个结果:引用Money类的每1行代码都不可能不要调动。有时候很幸运,你正是独具这几个代码的帮忙者,只要求自个儿向来重构就能够。但是Alice的事态就未有那样好了;多数公司都复用了他的代码。由此,她必要协和他们的代码库与友好的改造保持一致,只怕依然要经历一段极度难过、持久的正经弃用进度(deprecation process)。

有幸的是,Alice知道壹种更加好的消除办法,可防止止这一个令人头疼的范畴现身:使用Python内建的property装饰器。@property一般选拔在Python方法上,能够使得地将质量访问(attribute access)产生方法调用(method call)。比如,临时将Money类抛至一面,借使有1个象征人类的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被定义为1个措施,但却得以通过变量属性的方式访问。在最终一行代码中尚无()操作符;我并未调用full_name方法。大家所做的,能够说是成立了某种动态属性。

回去本文中的Money类,Iris对它作了之类修改:

# 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外,Iris还动用@dollars.setter创设了一个setter。Iris还对cents`属性作了近乎管理。

那正是说未来,鲍伯的代码要做哪些相应的改换呢?根本毫无改!

# 他的代码完全没有变动,但是却可以正常调用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  = 2
money.cents  = 20
print(message.format(money.dollars, money.cents))
# "I have 29 dollars and 32 cents."# 代码逻辑也没有问题。
money.cents  = 112
print(message.format(money.dollars, money.cents))
# "I have 30 dollars and 44 cents."

实际,全数应用了Money类的代码都无需开始展览修改。Bob不明了或根本不在乎Iris去除了类中的dollars和cents属性:他的代码仍旧和原先同样健康实践。唯壹修改过的代码正是Money类自个儿。

多亏出于Python中管理装饰器的方式,你能够在类中随便使用简便的品质。倘使您所写的类改动了管住景况的办法,你能够满怀信心地经过@property装饰器对这几个类(且唯有这么些类)举行修改。那是三个双赢的主意!相反,在Java等语言中,程序猿必须主动去定义访问属性的章程(比如getDollars或setCents)。

最终要指示大家:这种措施对于那多少个被别的技师和集体复用的代码最为重大。如若仅仅是在您自身一个爱抚的行使中开创二个好像Money的类,那么只要您转移了Money的接口,你只供给重构自个儿的代码就能够。这种情形下,你无需像上面说的那样采纳@property装饰器。

 protected]]() 取值和赋值 class Actress(): def __init__(self): self.name = 'TianXin' self.age = 5 类Actress中有五个...

往年,Python技术员Iris要筹划创立一个意味着金钱的类。她的第一个落到实处情势大假如下边那样:

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

#以法郎为根基货币的Money类的第四个版本

类Actress中有三个成员变量name和age。在外表对类的积极分子变量的操作,首要不外乎取值和赋值。简单的取值操作是x=object.var,轻松的赋值操作是object.var=value。

class Money:

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

    def __init__(self, dollars, cents):

使用 Getter 和 Setter 上述轻巧的取值和赋值操作,在有些情形下是无法满意要求的。比方,要是要限制Actress的年龄范围,那么只利用上述轻巧的赋值操作就不能满意要求了。getter和setter完毕那样的需求。

        self.dollars = dollars

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

        self.cents = cents

调用setAge函数可以兑现将变量_age的取值范围限定到低于30.

        #还会有其余一些艺术,大家临时不用理会

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

使用property property的定义是:
在那之中,fget是取值函数,fset是赋值函数,fdel是删除函数。使用property也完成上述对成员变量的取值限制。

        几个月大概几年以后。阿丽丝想要重构Money类的里边贯彻,不再记录英镑和美分,而是1味记录美分,因为如此做能够让有个别操作简单多数。上面是她很或许会作的改变:

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')

#Money类的第壹个版本

透过地点的定义后,能够像轻松取值和赋值操作同样操作age。譬如,

class Money:

>>> actress = Actress()
>>> actress.age
20
>>> actress.age = 18
>>> actress.age = 55

ValueError

    def __init__(self, dollars, cents):

使用@property 行使@property一样可以达成上述类的定义。

        self.total_cents = dollars * 100 cents

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

使用时的示范:

        幸运的是,Iris知道一种更加好的化解办法,能够免止这些令人高烧的层面出现:使用Python内建的property装饰器。@property相似选用在Python方法上,能够有效地将品质访问(attribute access)变成方法调用(method call)。比如,一时半刻将Money类抛至1头,假如有三个象征人类的Person类(class):

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

class Person:

Python2 和 Python3中使用property的区别 上述property示例在Python三的情状下有效。在Python第22中学,使用property时,类定义时索要继承object。不然,property的赋值操作不可采取。

    def __init__(self, first, last):        self.first = first

Python二下property的不利使用办法:

        self.last = last

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'

)

    @property

实例:飞速展开代码重构 从前,Python程序猿Iris要企图创制叁个表示金钱的类。她的率先个落到实处情势概略是下面那样:

    def full_name(self):

# 以美元为基础货币的Money类的首个版本
class Money:
  def __init__(self, dollars, cents):
    self.dollars = dollars
    self.cents = cents
    # 还有其他一些方法,我们暂时不必理会

        return '{} {}'.format(self.first, self.last)

本条类新兴被打包到八个PythonCurry,并且稳步地被许多两样的运用使用。举例,另三个团队中的Python程序猿Bob是如此使用Money类的:

        请注意full_name方法。除了在def语句上方装饰了@property之外,该格局的扬言未有何两样的地方。但是,那却改造了Person对象的运营格局

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  = 2
money.cents  = 20
print(message.format(money.dollars, money.cents))
# "I have 29 dollars and 32 cents."

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

这么使用并不曾错,不过却出现了代码可维护性的难题。你意识了吧?

>>> buddy.full_name

多少个月或许几年现在。阿丽丝想要重构Money类的内部贯彻,不再记录澳元和美分,而是唯有记录美分,因为如此做可以让有个别操作简易诸多。下边是她很恐怕会作的修改:

'Jonathan Doe'

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

        大家开掘,就算full_name被定义为3个措施,但却得以通过变量属性的章程访问。在结尾壹行代码中平素不()操作符;笔者并未调用full_name方法。大家所做的,能够说是创办了某种动态属性

那1更动带来二个后果:引用Money类的每1行代码都必须求调治。一时候很幸运,你正是全部这么些代码的拥护者,只须要团结一贯重构就能够。不过艾丽丝的图景就一直不比此好了;很多团体都复用了她的代码。由此,她索要和谐他们的代码库与和煦的修改保持一致,或许照旧要经历一段特别忧伤、长久的规范弃用进度(deprecation process)。


幸运的是,Iris知道1种更加好的化解办法,能够幸免这些令人头痛的范围出现:使用Python内建的property装饰器。@property一般采用在Python方法上,能够有效地将质量访问(attribute access)产生方法调用(method call)。举个例子,权且将Money类抛至三头,借使有一个表示人类的Person类(class):

回到本文中的Money类,阿丽丝对它作了如下修改:

class Person:
  def __init__(self, first, last):
    self.first = first
    self.last = last
  @property
  def full_name(self):
    return '{} {}'.format(self.first, self.last)

# Money类的结尾版本

代码样式分裂,是因为在此之前用的工具出难题了。—EarlGrey

class Money:

请注意full_name方法。除了在def语句上方装饰了@property之外,该措施的宣示没有怎么不一致的地点。但是,那却更动了Person对象的周转情势:

    def __init__(self, dollars, cents):        

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

            self.total_cents = dollars * 100 cents

小编们发掘,纵然full_name被定义为一个办法,但却得以经过变量属性的章程访问。在最后1行代码中尚无()操作符;作者并未有调用full_name方法。大家所做的,能够说是创办了某种动态属性。

    # Getter and setter for dollars...

重回本文中的Money类,阿丽丝对它作了如下修改:

    @property

# 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

    def dollars(self):

除了利用@property装饰器定义了dollars属性的getter外,艾丽丝还采纳@dollars.setter创立了四个setter。Alice还对cents`属性作了看似管理。

        return self.total_cents // 100;

那便是说今后,Bob的代码要做怎么着相应的修改呢?根本无须改!

    @dollars.setter

# 他的代码完全没有变动,但是却可以正常调用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  = 2
money.cents  = 20
print(message.format(money.dollars, money.cents))
# "I have 29 dollars and 32 cents."# 代码逻辑也没有问题。
money.cents  = 112
print(message.format(money.dollars, money.cents))
# "I have 30 dollars and 44 cents."

    def dollars(self, new_dollars):        

其实,全部应用了Money类的代码都没有供给开始展览退换。Bob不驾驭或根本不在乎Alice去除了类中的dollars和cents属性:他的代码依然和原先一样健康执行。唯1修改过的代码便是Money类本人。

            self.total_cents = 100 * new_dollars self.cents

万幸由于Python中管理装饰器的章程,你能够在类中随便使用轻巧的性情。假使您所写的类改造了管理境况的艺术,你能够满怀信心地因此@property装饰器对那几个类(且唯有那些类)进行更动。这是2个共赢的方法!相反,在Java等语言中,程序猿必须主动去定义访问属性的办法(比如getDollars或setCents)。

      # And the getter and setter for cents.

末尾要唤醒咱们:这种方法对于那个被其它技士和组织复用的代码最为根本。即便仅仅是在你本人叁个保安的接纳中创制贰个类似Money的类,那么1旦你改造了Money的接口,你只必要重构本人的代码就能够。这种气象下,你没有须求像上边说的那么选用@property装饰器。

    @property

你或者感兴趣的稿子:

  • python怎么着定义带参数的装饰器
  • Python装饰器(decorator)定义与用法详解
  • 介绍Python的@property装饰器的用法
  • Python中的种种装饰器详解
  • 深切明白python中的闭包和装饰器
  • Python装饰器的函数式编制程序详解
  • 详解Python中的装饰器、闭包和functools的科目
  • 巧用Python装饰器 免去调用父类构造函数的劳顿
  • Python中的多种装饰器
  • python重试装饰器示例
  • Python自定义装饰器原理与用法实例剖判

    def cents(self):

        return self.total_cents % 100;

    @cents.setter

    def cents(self, new_cents):        

            self.total_cents = 100 * self.dollars new_cents

本文由必发88手机版发布,转载请注明来源:property装饰器的用法,飞快重构Python代码