"/>
侧边栏壁纸
博主头像
PySuper 博主等级

千里之行,始于足下

  • 累计撰写 243 篇文章
  • 累计创建 15 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

Python @property

PySuper
2025-03-22 / 0 评论 / 0 点赞 / 9 阅读 / 0 字
温馨提示:
所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

在Python中,直接暴露类属性可能会导致数据被意外修改,破坏封装性。而SetterGetter方法提供了一种更安全、更灵活的方式来控制属性的访问和修改。

Python的 @property装饰器 让这一切变得极其简单!今天,我们就来深入探讨如何用它优雅地管理类的属性。

为什么需要Setter和Getter

假设你有一个Person类,直接暴露age属性可能会有问题:

class Person:
    def __init__(self, age):
        self.age = age  # 直接暴露属性


p = Person(25)
p.age = -10  # 年龄可以是负数?不合理!

问题

  • 无法对赋值进行验证(如age不能为负数)。

  • 无法动态计算属性(如根据birth_year计算age)。

  • 破坏面向对象的封装性

解决方案:使用SetterGetter

传统Setter/Getter写法(Java风格)

在Java等语言中,Setter/Getter通常是这样的:

class Person:
    def __init__(self, age):
        self._age = age  # 私有属性,外部无法直接访问

    def get_age(self):
        return self._age  # 定义 getter方法,返回私有属性

    def set_age(self, age):
        if 0 <= age <= 150:
            self._age = age
        else:
            raise ValueError("年龄不在0-150之间")  # 定义 setter方法,对年龄进行校验


p = Person(25)
print(p.get_age())  # 25
p.set_age(-30)

缺点

  • 代码冗长,调用方式不够直观(p.set_age(30) vs p.age = 30)。

Pythonic方式:@property装饰器

Python提供了@property,让Setter/Getter的调用像普通属性一样自然!

(1)基本用法

class Person:
    def __init__(self, age):
        self._age = age  # 私有属性,外部无法直接访问

    @property  # 定义 getter方法,返回私有属性
    def age(self):
        return self._age

    @age.setter  # 定义 setter方法,对年龄进行校验
    def age(self, age):
        if 0 <= age <= 150:
            self._age = age
        else:
            raise ValueError("年龄不在0-150之间")


p = Person(25)
print(p.age)  # 25(像属性一样访问)
p.age = 30  # 正常赋值
p.age = -10  # 报错:ValueError

优势:
✅ 调用方式更直观(
p.age 而不是 p.get_age())。
✅ 仍然可以控制赋值逻辑。

(2)只读属性(没有Setter)

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def area(self):  # 只读,动态计算
        return 3.14 * self._radius**2


c = Circle(5)
print(c.area)  # 78.5
c.area = 100  # 报错:AttributeError(没有setter)

(3)删除属性(@deleter)

class TempData:
    def __init__(self, data):
        self._data = data

    @property
    def data(self):
        return self._data

    @data.deleter
    def data(self):
        print("数据已被删除!")
        del self._data


t = TempData("秘密数据")
del t.data  # 输出:"数据已被删除!"

实际应用场景

(1)数据验证

class User:
    def __init__(self, username):
        self._username = username

    @property
    def username(self):
        return self._username

    @username.setter
    def username(self, value):
        if not value.isalnum():
            raise ValueError("用户名只能包含字母和数字!")
        self._username = value


u = User("Alice123")
u.username = "Bob_456"  # 报错:ValueError

(2)动态计算属性

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

    @fahrenheit.setter
    def fahrenheit(self, value):
        self._celsius = (value - 32) * 5 / 9


t = Temperature(0)
print(t.fahrenheit)  # 32.0
t.fahrenheit = 100
print(t._celsius)  # 37.777...

(3)兼容旧代码(属性改名但API不变)

class LegacyClass:
    def __init__(self, value):
        self._internal_value = value  # 新变量名

    @property
    def value(self):  # 保持旧接口
        return self._internal_value

    @value.setter
    def value(self, v):
        self._internal_value = v


obj = LegacyClass(10)
print(obj.value)  # 10(外部仍然用.value访问)

总结

🎯 @property 的核心优势
数据封装:隐藏内部实现,防止非法修改。
动态计算:属性可以实时计算(如
areafahrenheit)。
兼容性:可以在不改变外部API的情况下修改内部逻辑。

💡 最佳实践

  • 优先使用@property,而不是直接暴露属性。

  • 对需要控制的属性使用Setter进行验证。

  • 只读属性可以不加@setter

class YourClass:
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        if new_value < 0:
            raise ValueError("不能为负数!")
        self._value = new_value

🚀 现在就去试试@property,让你的Python类更健壮、更优雅!

0

评论区