【Python】@property装饰器

主要内容是翻译自:https://www.programiz.com/python-programming/property

目录

没有getter和setter的类

使用getter和setter

The property Class

@property装饰器


Python编程为我们提供了一个内置的@property装饰器,该装饰器使面向对象编程中的getter和setter的使用更加容易。

回顾一下,什么是装饰器:【Python】装饰器

为什么需要@property装饰器

没有getter和setter的类

建立一个以摄氏度为单位存储温度的。并实现一种将温度转换为华氏度的方法。一种方法如下:

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

创建对象,并调用temperature属性:

# Basic method of setting and getting attributes in Python
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32


# Create a new object
human = Celsius()

# Set the temperature
human.temperature = 37

# Get the temperature attribute
print(human.temperature) # 37  # 类属性的使用: 类名.属性名
print(human.__dict__) # {'temperature': 37}


# Get the to_fahrenheit method
print(human.to_fahrenheit()) # 98.60000000000001

使用getter和setter

更正确的类声明:隐藏属性temperature(将其设为私有),并定义新的getter和setter方法来对其进行操作。

# Making Getters and Setter methods
class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)

    # setter method
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value  # 类变量,在Celsius类中共享

    # getter method
    def get_temperature(self):
        return self._temperature  # 私有变量

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32


if __name__ == '__main__':
    # Create a new object, set_temperature() internally called by __init__
    human = Celsius(37)

    # Get the temperature attribute via a getter
    print(human.get_temperature()) # 37  # 现在类变量的使用从.转变为调用get方法

    # Get the to_fahrenheit method, get_temperature() called by the method itself
    print(human.to_fahrenheit()) # 98.60000000000001

    # new constraint implementation
    human.set_temperature(-300)

    # Get the to_fahreheit method
    print(human.to_fahrenheit())
    """
    Traceback (most recent call last):
    File "F:/weiwenjing5/PycharmProjects/studyPython/study_property3.py", line 31, in <module>
    human.set_temperature(-300)
    File "F:/weiwenjing5/PycharmProjects/studyPython/study_property3.py", line 9, in set_temperature
    raise ValueError("Temperature below -273.15 is not possible.")
    ValueError: Temperature below -273.15 is not possible.
    """

However, the bigger problem with the above update is that all the programs that implemented our previous class have to modify their code from obj.temperature to obj.get_temperature() and all expressions like obj.temperature = val to obj.set_temperature(val).

简单来说,我们原来使用类变量只需要 类.属性名 就可以访问了,但是现在需要 类.get方法() 来访问变量。

The property Class

We added a print() function inside get_temperature() and set_temperature() to clearly observe that they are being executed.

The last line of the code makes a property object temperature. Simply put, property attaches some code (get_temperature and set_temperature) to the member attribute accesses (temperature).

说明以下代码:

当创建对象时,__init__()将调用该方法。此方法已行self.temperature = temperature。此表达式自动调用set_temperature()

同样,任何访问,例如c.temperature自动调用get_temperature()。这就是property的作用。

# using property class
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    # getter
    def get_temperature(self):
        print("Getting value...")
        return self._temperature

    # setter
    def set_temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible")
        self._temperature = value

    # creating a property object
    temperature = property(get_temperature, set_temperature)
    """
     a property object temperature. Simply put, 
     property attaches some code (get_temperature and set_temperature) to the member attribute accesses (temperature)
     
     property将 get_temperature 和 set_temperature 方法,附加到temperature的类变量中
    """


if __name__ == '__main__':
    human = Celsius(37)

    print('******************************')
    print(human.temperature)
    # print(human.__dict__) # {'_temperature': 37}
    print(human.to_fahrenheit())  # 调用方法: 类.方法
    print('------------------------------')
    human.temperature = -300


    """
    Setting value...
    ******************************
    Getting value...
    37
    Getting value...
    98.60000000000001
    ------------------------------
    Setting value...
    Traceback (most recent call last):
      File "F:/weiwenjing5/PycharmProjects/studyPython/study_property4.py", line 37, in <module>
        human.temperature = -300
      File "F:/weiwenjing5/PycharmProjects/studyPython/study_property4.py", line 18, in set_temperature
        raise ValueError("Temperature below -273.15 is not possible")
    ValueError: Temperature below -273.15 is not possible
    
    Process finished with exit code 1

    """

实际温度值存储在私有_temperature 变量中。该temperature属性是为该私有变量提供接口的属性对象。

@property装饰器

在Python中,property()是一个内置函数,用于创建并返回一个property对象。该函数的语法为:

property(fget=None, fset=None, fdel=None, doc=None)
  • fget 是获取属性值的函数
  • fset 是设置属性值的功能
  • fdel 是删除属性的功能
  • doc 是一个字符串(如评论)

从实现中可以看出,这些函数参数是可选的。因此,可以简单地如下创建属性对象。

>>> property()
<property object at 0x0000000003239B38>

Property对象有三种方法,getter()setter(),和deleter()指定fgetfsetfdel在稍后的点。这意味着,该行:

temperature = property(get_temperature,set_temperature)

可以细分为:

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)

这两段代码是等效的。

熟悉Python Decorators的程序员可以认识到上述构造可以实现为装饰器。

我们甚至无法定义名称get_temperatureset_temperature由于它们是不必要的,因此会污染类名称空间。

为此,我们temperature在定义getter和setter函数的同时重用了名称。让我们看一下如何将其实现为装饰器:

# property()是一个内置函数,用于创建并返回一个property对象。该函数的语法为:
# property(fget=None, fset=None, fdel=None, doc=None)

"""
fget 是获取属性值的函数
fset 是设置属性值的功能
fdel 是删除属性的功能
doc 是一个字符串(如评论)
"""

# Property对象有三种方法,getter(),setter(),和deleter()指定fget,fset并fdel在稍后的点。这意味着,该行:
"""
temperature = property(get_temperature,set_temperature)

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
"""


# Using @property decorator
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Getting value...")
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273 is not possible")
        self._temperature = value

if __name__ == '__main__':
    # create an object
    human = Celsius(37)
    print('-'*10)
    print(human.temperature)
    print('-' * 10)
    print(human.to_fahrenheit())
    print('-' * 10)
    coldest_thing = Celsius(-300)

    """
    Setting value...
    ----------
    Getting value...
    37
    ----------
    Getting value...
    98.60000000000001
    ----------
    Setting value...

    Traceback (most recent call last):
      File "F:/weiwenjing5/PycharmProjects/studyPython/study_property5.py", line 54, in <module>
        coldest_thing = Celsius(-300)
      File "F:/weiwenjing5/PycharmProjects/studyPython/study_property5.py", line 29, in __init__
        self.temperature = temperature
      File "F:/weiwenjing5/PycharmProjects/studyPython/study_property5.py", line 43, in temperature
        raise ValueError("Temperature below -273 is not possible")
    ValueError: Temperature below -273 is not possible

    """

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值