Python 面向对象编程 —— 属性的装饰器:@property 和 @setter

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 可以增强类的封装性,使得数据的获取和设置更加灵活和安全。

通过这两个装饰器,你可以简化对属性的控制,提升代码的可读性和可维护性。

相关推荐
全栈小刘2 分钟前
ChatGPT账号打通OpenClaw?Codex又整了个“电子宠物”,开发者这下真坐不住了
后端
陈随易14 分钟前
bun将会支持Bun.image,你怎么看?
前端·后端·程序员
念何架构之路22 分钟前
Go Web基础和Http演进
开发语言·后端·golang
绿草在线31 分钟前
SpringBoot项目实战:从零搭建高效开发环境
java·spring boot·后端
longxibo37 分钟前
【第1章 环境搭建与项目结构解析】
java·后端·流程图
程序员老邢1 小时前
【产品底稿 11】架构规整收官:从混乱到清晰,工程结构、表命名、模块分层一次性定型
后端·架构·springboot·产品底稿·架构规整·模块分层·数据库规范
IT_陈寒2 小时前
React的useEffect把我坑惨了,这些闭包陷阱真要命
前端·人工智能·后端
薪火铺子2 小时前
SpringMVC请求处理流程源码解析(第1篇):请求入口与处理器映射
java·后端·spring
_Evan_Yao2 小时前
从 IP 路由到 Agent 路由:最长前缀匹配如何帮你分发任务?
java·网络·后端·网络协议·tcp/ip
.柒宇.2 小时前
AI掘金头条项目 Docker Compose 部署完整教程(附踩坑记录)
运维·后端·python·docker·容器·fastapi