Examples to explain the usage of @property decorator in Python programming

WBOY
Release: 2016-07-21 14:53:19
Original
1071 people have browsed it

Value and assignment

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


There are two member variables name and age in class Actress. External operations on class member variables mainly include value acquisition and assignment. The simple value operation is x=object.var, and the simple assignment operation is object.var=value.

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

Copy after login

Use Getter and Setter
The above simple value acquisition and assignment operations cannot meet the requirements in some cases. For example, if you want to limit the age range of Actress, then just using the above simple assignment operation will not meet the requirements. Getters and setters implement such requirements.

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

Copy after login

Call the setAge function to limit the value range of the variable _age to less than 30.

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

Copy after login

Use property
The definition of
property is:
Among them, fget is the value function, fset is the assignment function, and fdel is the deletion function. Using property also implements the above-mentioned value restrictions on member variables.

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

Copy after login

After the above definition, age can be operated like simple value acquisition and assignment operations. For example,

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

ValueError

Copy after login

Use @property
Using @property can also achieve the definition of the above class.

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

Copy after login

Example of usage:

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

The difference between using properties in Python2 and Python3
The above property examples are valid in the Python3 environment. In Python2, when using property, the class definition needs to inherit object. Otherwise, the property assignment operation cannot be used.

The correct way to use property under Python2:

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'

)

Copy after login

Example: Quick code refactoring
Once upon a time, Alice, a Python programmer, wanted to create a class that represented money. Her first implementation is probably as follows:

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

Copy after login

This class was later packaged into a Python library and slowly used by many different applications. For example, Bob, a Python programmer on another team, uses the Money class like this:

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."

Copy after login

There is nothing wrong with using it this way, but it does cause problems with code maintainability. Did you find out?

A few months or years later. Alice wants to refactor the internal implementation of the Money class so that it no longer records dollars and cents, but only cents, because doing so will make certain operations much simpler. Here are the changes she is likely to make:

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

Copy after login

This modification has one consequence: every line of code that references the Money class must be adjusted. Sometimes you are lucky and you are the maintainer of all this code and you just need to refactor it directly yourself. But Alice's situation was not so good; many teams reused her code. Therefore, she would need to reconcile their code base with her changes, perhaps even going through a particularly painful and lengthy formal deprecation process.

Fortunately, Alice knows a better solution to avoid this headache: use Python's built-in property decorator. @property is generally used on Python methods, which can effectively turn attribute access into method call. For example, let’s put aside the Money class for a moment and imagine a Person class that represents humans:

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

Copy after login

The code style is different because there was a problem with the tool I used before. —EarlGrey

Please note the full_name method. There is nothing different about the declaration of the method except that it is decorated with @property above the def statement. However, this changes the way the Person object works:

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

Copy after login

We found that although full_name is defined as a method, it can be accessed through variable attributes. There is no () operator in the last line of code; I am not calling the full_name method. What we've done is created some sort of dynamic property, so to speak.

Back to the Money class in this article, Alice made the following modifications to it:

# 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

Copy after login

In addition to using the @property decorator to define the getter of the dollars property, Alice also creates a setter using @dollars.setter. Alice also performed similar processing on the cents` attribute.

So now, what corresponding modifications should be made to Bob’s code? No need to change at all!

# 他的代码完全没有变动,但是却可以正常调用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."

Copy after login

In fact, all code using the Money class does not need to be modified. Bob doesn't know or care that Alice removed the dollars and cents attributes from the class: his code still executes normally as before. The only code that has been modified is the Money class itself.

Precisely because of the way decorators are handled in Python, you can freely use simple attributes in your classes. If you write a class that changes the way it manages state, you can confidently make changes to that class (and only that class) through the @property decorator. This is a win-win approach! In contrast, in languages ​​such as Java, programmers must actively define methods to access properties (such as getDollars or setCents).

Finally, a reminder: this approach is most important for code that is reused by other programmers and teams. Assuming you just create a class like Money in an application you maintain, then if you change the interface of Money, you only need to refactor your own code. In this case, you don't need to use the @property decorator as mentioned above.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!