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

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

在 Python 中,@property@setter 装饰器用于控制类属性的访问和赋值。它们能够帮助我们创建具有getter和setter功能的属性,同时保留类的封装性。

  • Getter 是一个方法,用于 获取对象的属性值;它通常是只读的,不会修改对象的属性,只是返回属性的当前值。
  • 通过 getter 方法,外部代码可以间接访问对象的属性,即使这些属性是私有的(以 _ 或 __ 开头)。
  • Setter 是一个方法,用于 设置对象的属性值;它通常会对传入的值进行验证或处理,然后将其赋给对象的属性。
  • 通过 setter 方法,外部代码可以修改对象的属性,但 setter 方法可以对赋值过程进行控制,比如限制值的范围,或处理一些特殊逻辑。

1. @property 装饰器

@property 装饰器将一个方法转化为属性,使得方法可以像属性一样被访问。

作用:
  • @property 装饰器将方法转换为属性,使得方法可以像访问普通属性一样被调用。
  • 用于将方法封装成只读属性,控制外部对某个属性的读取行为。
使用场景:
  • 在需要计算一个值的时候,使用@property可以避免每次访问时都调用一个函数。
  • 通过@property,你可以限制类外部的写入操作,仅允许对特定属性进行控制和修改。
语法实例:
class 类名:

    @property
    def 方法名(self):
        方法代码

在需要将方法变成属性的上面写@property即可将方法变成属性

代码示例:
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 看作是一种拦截器

使用场景:
  • 想要限制某个属性的值,比如限制范围或进行格式检查。
  • 需要在设置属性值时,执行额外的操作,如更新其他相关值。
示例语法:
class 类名:
   
    #先设置将一个方法定义为属性
    @property
    def 方法名(self):
        代码
    
    
    @设置成属性的方法名.setter
    def 方法名(self, value):
        代码

示例代码(通过计算圆的直径为例子):
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 一起使用,这样可以实现对属性值的完全控制,并同时提供更直观的接口。

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

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

### Python 面向对象编程概念 面向对象编程(Object-Oriented Programming, OOP)是一种基于类实例化对象的编程范式。这种编程方式允许开发者创建可重用的对象模型来表示现实世界中的实体。 #### 类定义与初始化方法 在Python中,通过`class`关键字定义新类型的对象[^1]: ```python class Book: def __init__(self, title, author): self.title = title self.author = author ``` 这段代码展示了如何声明一个名为 `Book` 的类,并为其提供了一个构造函数 `_ _init_ _()` 来设置属性 `title` `author`。 #### 封装私有成员变量 为了保护某些数据不被外部直接访问,在Python里可以利用双下划线前缀命名约定实现伪私有的字段或方法[^2]: ```python class Book: def __init__(self, title, author): self.__title = title # 私有属性 self._author = author # 受保护的属性 @property def title(self): return self.__title @title.setter def title(self, value): if isinstance(value, str): self.__title = value else: raise ValueError("Title must be a string.") ``` 这里使用了装饰器 `@property` 创建只读属性以及相应的 setter 方法用于修改这些受控的数据项。 #### 继承机制 继承使得子类能够获得父类的功能并扩展自己的行为。这有助于构建层次化的软件架构。 ```python class EBook(Book): def __init__(self, title, author, format_type="PDF"): super().__init__(title, author) self.format_type = format_type def read_ebook(self): print(f"Reading {self.title} as an eBook in {self.format_type}.") ``` 上述例子说明了怎样让新的电子书类别继承自普通书籍的同时增加了特定于该形式的新功能——阅读格式支持。 #### 多态性 多态意味着相同的操作作用于不同类型的对象会产生不同的效果。它通常体现在方法覆盖上,即子类重新实现了来自超类的方法以适应具体需求。 ```python def describe_book(book_instance): book_instance.describe() class PaperBook(Book): def describe(self): print(f"This is a paper version of '{self.title}' by {self.author}") ebook_example = EBook('The Great Gatsby', 'Fitzgerald') paperbook_example = PaperBook('War and Peace', 'Tolstoy') describe_book(ebook_example) # Output: Reading The Great Gatsby as an eBook... describe_book(paperbook_example) # Output: This is a paper version of War and Peace ... ``` 在这个场景中,尽管调用了相同的描述接口,但由于传入的具体类型差异导致实际执行的动作有所区别。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序小武

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值