ZetCode

Python property 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨了 Python 的 property 函数,该函数创建具有 getter、setter 和 deleter 方法的托管属性。我们将介绍基本用法、装饰器语法和实际示例。

基本定义

property 函数返回一个 property 属性。它提供了一种使用方法封装实例属性访问的方式。这使得数据验证、计算属性和只读属性成为可能。

主要特点:接受可选的 getter、setter、deleter 和文档字符串参数。返回一个 property 对象,该对象在访问时使用这些方法。它是 Python 中的内置描述符类型。

基本 Property 用法

这是一个简单的用法示例,展示了如何为温度类创建一个带有验证的 property。该 property 确保温度保持在绝对零度以上。

basic_property.py
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    def get_celsius(self):
        return self._celsius
    
    def set_celsius(self, value):
        if value < -273.15:
            raise ValueError("Temperature below absolute zero")
        self._celsius = value
    
    celsius = property(get_celsius, set_celsius)

temp = Temperature(25)
print(temp.celsius)  # 25
temp.celsius = 30
print(temp.celsius)  # 30
try:
    temp.celsius = -300  # Raises ValueError
except ValueError as e:
    print(e)

此示例演示了如何使用单独的 getter 和 setter 方法创建 property。该 property 确保温度值在物理上有效,同时保持一个干净的接口。

_celsius 命名约定表明它是一个受保护的属性。用户与 celsius property 交互,而不是与属性交互。

Property 装饰器语法

Python 的装饰器语法提供了一种更简洁的方式来定义 property。此示例演示了使用装饰器的相同温度类。

decorator_property.py
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Temperature below absolute zero")
        self._celsius = value

temp = Temperature(25)
print(temp.celsius)  # 25
temp.celsius = -100
print(temp.celsius)  # -100

装饰器语法更具可读性,并将相关方法组合在一起。@property 装饰器创建 getter,而 @celsius.setter 创建 setter。

这种方法在现代 Python 代码中更受欢迎,因为它清楚地表明了哪些方法属于该 property。

只读 Property

Property 可以通过省略 setter 来创建只读属性。此示例显示了一个具有计算的只读面积 property 的圆形类。

readonly_property.py
import math

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    @property
    def area(self):
        return math.pi * self.radius ** 2

circle = Circle(5)
print(circle.area)  # 78.53981633974483
try:
    circle.area = 100  # Raises AttributeError
except AttributeError as e:
    print("Can't set area:", e)

area property 从半径计算得出,不能直接设置。尝试设置它会引发 AttributeError

此模式对于仅当其源属性更改时才应更改的派生属性很有用。

带有 Deleter 的 Property

Property 还可以定义 deleters 以进行清理操作。此示例显示了一个具有基于 property 的资源管理的文件处理程序类。

deleter_property.py
class FileHandler:
    def __init__(self, filename):
        self._filename = filename
        self._file = open(filename, 'r')
    
    @property
    def file(self):
        return self._file
    
    @file.deleter
    def file(self):
        if self._file:
            self._file.close()
            self._file = None

handler = FileHandler('example.txt')
print(handler.file.read(10))
del handler.file  # Closes the file

deleter 确保在删除 property 时进行适当的资源清理。这比依赖 __del__ 或上下文管理器更明确。

该 property 提供了对文件对象的受控访问,同时保持了在需要时正确关闭它的能力。

动态 Property

Property 可以从其他属性动态计算值。此示例显示了一个具有动态宽度/高度 property 的矩形类。

dynamic_property.py
class Rectangle:
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2
    
    @property
    def width(self):
        return abs(self.x2 - self.x1)
    
    @width.setter
    def width(self, value):
        if value <= 0:
            raise ValueError("Width must be positive")
        self.x2 = self.x1 + value
    
    @property
    def height(self):
        return abs(self.y2 - self.y1)
    
    @height.setter
    def height(self, value):
        if value <= 0:
            raise ValueError("Height must be positive")
        self.y2 = self.y1 + value

rect = Rectangle(0, 0, 10, 20)
print(rect.width, rect.height)  # 10 20
rect.width = 15
print(rect.width)  # 15

宽度和高度 property 是从坐标计算得出的,但也可以设置,这将更新坐标。这保持了数据一致性。

当您想要呈现相同底层数据的不同视图,同时保持一切同步时,此方法非常有用。

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程