Python 面向对象编程 ------ 属性的装饰器:@property
和 @setter
在 Python 中,@property
和 @setter
装饰器用于控制类属性的访问和赋值。它们能够帮助我们创建具有getter和setter功能的属性,同时保留类的封装性。
- Getter 是一个方法,用于 获取对象的属性值;它通常是只读的,不会修改对象的属性,只是返回属性的当前值。
- 通过 getter 方法,外部代码可以间接访问对象的属性,即使这些属性是私有的(以
_
或__
开头)。 - Setter 是一个方法,用于 设置对象的属性值;它通常会对传入的值进行验证或处理,然后将其赋给对象的属性。
- 通过 setter 方法,外部代码可以修改对象的属性,但 setter 方法可以对赋值过程进行控制,比如限制值的范围,或处理一些特殊逻辑。
1. @property
装饰器
@property
装饰器将一个方法转化为属性,使得方法可以像属性一样被访问。
作用:
@property
装饰器将方法转换为属性,使得方法可以像访问普通属性一样被调用。- 用于将方法封装成只读属性,控制外部对某个属性的读取行为。
使用场景:
- 在需要计算一个值的时候,使用
@property
可以避免每次访问时都调用一个函数。 - 通过
@property
,你可以限制类外部的写入操作,仅允许对特定属性进行控制和修改。
语法实例:
python
class 类名:
@property
def 方法名(self):
方法代码
在需要将方法变成属性的上面写
@property
即可将方法变成属性
代码示例:
python
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def radius_attribute(self):
return self.radius
#@property
def area(self):
return 3 * self.radius
circle = Circle(5)
print(circle.radius_attribute)
print(circle.area())
输出示例:
5
15
解释:
circle = Circle(5)
:实例一个对象,传入参数5,并赋值给circle变量print(circle.radius_attribute)
:访问radius_attribute属性,因为添加了@property
装饰器,它就从方法变成了属性print(circle.area())
:调用area方法,但没添加就@property
装饰器就正常调用
2. @setter
装饰器
@setter
装饰器是与 @property
配合使用的,用于设置属性值。当你通过属性赋值时,@setter
装饰器能够捕获赋值操作并定义相应的行为。
作用:
@setter
装饰器可以定义属性的设置规则,进行验证或修改值。- 它让你能够在对属性赋值时,执行一些逻辑,控制哪些值可以被接受。
-
可以把
@setter
看作是一种拦截器
使用场景:
- 想要限制某个属性的值,比如限制范围或进行格式检查。
- 需要在设置属性值时,执行额外的操作,如更新其他相关值。
示例语法:
python
class 类名:
#先设置将一个方法定义为属性
@property
def 方法名(self):
代码
@设置成属性的方法名.setter
def 方法名(self, value):
代码
示例代码(通过计算圆的直径为例子):
python
class Circle:
def __init__(self, radius):
self._radius = radius # 私有属性,避免直接访问
@property
def radius(self):
"""获取半径"""
return self._radius
@radius.setter
def radius(self, value):
"""设置半径"""
self._radius = value
@property
def diameter(self):
"""计算圆的直径"""
return 2 * self._radius
# 示例代码
circle = Circle(5)
print(circle.radius) # 通过 @property 装饰器,获取半径值,输出 5
circle.radius = 10 # 通过 `@radius.setter` 装饰器,半路拦截修改半径值为 10
print(circle.radius) # 获取设置后的半径值,输出 10
print(circle.diameter) # 通过 @property 获取直径值,输出 20
输出示例:
5
10
20
解释:
-
@radius.setter
:当你使用@property
你使用@property
装饰器将方法变成属性之后,你可能还希望给这个属性设置一个 setter 方法,以便修改属性的值。这个 setter 方法会在你对该属性进行赋值时自动调用 -
circle = Circle(5)
:实例一个对象,传入参数数字5,并赋值给circle变量 -
print(circle.radius)
: 通过@property
装饰器,获取半径值,输出 5 -
circle.radius = 10
:通过@radius.setter
装饰器,半路拦截修改半径值为 10 -
print(circle.radius)
:获取半路拦截修改半径值,输出 10 -
print(circle.diameter)
:通过@property
变成属性后,访问获取直径值,输出 20
这个过程就是将初始的值5修改为10,然后计算。
3. 结合使用 @property
和 @setter
在实际开发中,我们常常将 @property
和 @setter
一起使用,这样可以实现对属性值的完全控制,并同时提供更直观的接口。
示例代码:
python
class BankAccount:
# 初始化方法,接受一个初始余额并将其赋值给私有属性 _balance
def __init__(self, balance):
self._balance = balance # 私有变量用于存储账户余额
# 定义一个属性方法 (getter),返回当前余额
@property
def balance(self):
return self._balance
# 定义一个 setter 方法,用于设置余额。这里加入了负余额检查
@balance.setter
def balance(self, amount):
# 如果传入的金额为负数,抛出异常
if amount < 0:
raise ValueError("余额不能为负数")
self._balance = amount # 更新余额
# 存款方法,将指定金额添加到余额中
def deposit(self, amount):
self.balance += amount # 使用 setter 更新余额
# 取款方法,确保余额足够才能进行取款
def withdraw(self, amount):
# 如果取款金额大于当前余额,抛出异常
if amount > self.balance:
raise ValueError("余额不足")
self.balance -= amount # 使用 setter 更新余额
# 创建一个 BankAccount 对象,初始余额为 1000
account = BankAccount(1000)
# 输出当前余额,使用 getter 方法
print(account.balance) # 输出 1000
# 存款 500 元,余额应该变为 1500
account.deposit(500)
print(account.balance) # 输出 1500
# 通过 setter 方法直接设置余额为 2000
account.balance = 2000
print(account.balance) # 输出 2000
# 下面的操作会抛出异常
# account.balance = -100 # 会抛出 ValueError: 余额不能为负数
总结
@property
让方法可以像属性一样被访问。@setter
让你在给属性赋值时可以控制行为,并且实现数据验证、修改等功能。- 使用
@property
和@setter
可以增强类的封装性,使得数据的获取和设置更加灵活和安全。
通过这两个装饰器,你可以简化对属性的控制,提升代码的可读性和可维护性。