property() 函数及@property
装饰器
在Python中,property()
函数和@property
装饰器通常用于创建和管理类的属性。它们提供了一种控制类属性访问的机制,允许你在不改变类外部接口的情况下,在获取、设置或删除属性时添加自定义逻辑。
property()
函数
property()
函数可以在不使用装饰器的情况下创建属性。它通常用于老式的代码或者在需要动态创建属性的时候。
property()
函数最多可以接受四个参数:
fget
: 获取属性值的函数。fset
: 设置属性值的函数。fdel
: 删除属性的函数。doc
: 创建属性的文档字符串。
使用property()
函数的一个例子:
class Circle:
def __init__(self, radius):
self._radius = radius
def get_radius(self):
return self._radius
def set_radius(self, value):
if value >= 0:
self._radius = value
else:
raise ValueError("Radius cannot be negative")
def del_radius(self):
del self._radius
radius = property(get_radius, set_radius, del_radius, "I am the 'radius' property.")
c = Circle(5)
print(c.radius) # 输出: 5
c.radius = 10 # 正确设置半径
print(c.radius) # 输出: 10
# c.radius = -2 # 尝试设置负数半径将抛出 ValueError
print('查看属性的文档字符串:' + c.radius.__doc__)
# 会输出"I am the 'radius' property."
del c.radius #会执行del_radius
@property
装饰器
@property
装饰器是一个更加现代和优雅的方式来创建属性。它使你能够轻松地将一个方法转变为一个看似只读的属性,并且可以选择性地为这个属性添加setter和deleter。
在Python中,@property
装饰器是一个内置装饰器,它允许你将一个方法变换成属性的形式来访问。这可以让你在不改变类接口的前提下,将一个类的方法调用变得像是访问一个简单的属性一样。
当你使用@property
装饰一个方法时,这个方法会在你访问它时被隐式调用,不需要在调用时添加括号。这通常用于当你希望方法的行为看起来像是访问一个属性,但在访问时需要执行一些计算或逻辑时。
这里有一个简单的例子来演示如何使用@property
:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""Get the radius of the circle."""
return self._radius
@property
def diameter(self):
"""Calculate diameter using the radius."""
return self._radius * 2
@property
def area(self):
"""Calculate area using the radius."""
return 3.1415 * self._radius * self._radius
# 创建一个圆的实例
c = Circle(5)
# 通过属性的方式访问radius、diameter和area
print(c.radius) # 输出: 5
print(c.diameter) # 输出: 10
print(c.area) # 输出: 78.5375
在这个例子中,radius
, diameter
和 area
被当做属性来访问,尽管diameter
和area
背后实际上是通过方法计算得出的。这样,你就可以封装复杂的行为,同时保持简单的接口。
@property
还有一个互补的装饰器@<property_name>.setter
,它可以让你定义一个setter方法,这个方法在你设置属性值的时候被调用。
这是一个如何使用setter的例子:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""Get the radius of the circle."""
return self._radius
@radius.setter
def radius(self, value):
"""Set the radius of the circle."""
if value >= 0:
self._radius = value
else:
raise ValueError("Radius cannot be negative")
# 创建一个圆的实例
c = Circle(5)
print(c.radius) # 输出: 5
# 设置新的半径
c.radius = 10
print(c.radius) # 输出: 10
# 尝试设置一个负数半径会抛出错误
# c.radius = -2 # 将抛出ValueError
在这个例子中,可以看到如何控制属性设置的逻辑。试图设置一个负数的半径将会引发ValueError
。通过这种方式,@property
和@<property_name>.setter
提供了一种很好的封装和验证属性值的方法。