在Python面向对象编程中,类的属性如果直接暴露给外部,很容易被赋上不符合预期的值,比如年龄被设置为负数、成绩超过满分上限等。@property装饰器就是用来解决这类问题的工具,它可以将类的方法转换为类似属性的访问方式,同时支持对属性的读取、修改、删除逻辑进行自定义控制。
@property装饰器的核心作用
@property装饰器的主要作用有两个,一是让方法可以像属性一样被调用,简化代码的访问逻辑,二是通过自定义getter、setter、deleter方法,对属性的操作进行约束,实现属性的保护。
在没有使用@property的时候,如果我们想获取或修改一个需要校验逻辑的属性,通常需要定义get_xxx和set_xxx这样的方法,调用的时候需要加括号,不够直观。使用@property之后,我们可以把这些方法伪装成属性,调用的时候不需要加括号,和直接访问属性的体验一致,同时还能在背后执行校验逻辑。
@property的基础使用方法
使用@property装饰器需要配合对应的setter和deleter装饰器,分别对应属性的读取、修改、删除操作。下面通过一个简单的示例来展示基础用法。
定义只读属性
如果只需要获取属性的值,不需要修改,可以只使用@property装饰器定义getter方法。
class User:
def __init__(self, name):
self._name = name # 下划线开头表示内部属性,不建议外部直接访问
@property
def name(self):
# 定义name属性的getter方法,返回内部存储的值
return self._name
# 创建实例
user = User("张三")
# 像访问属性一样调用name方法,不需要加括号
print(user.name) # 输出:张三
# 尝试修改会报错,因为没有定义setter方法
# user.name = "李四" # 会抛出AttributeError
定义可读可写的属性
如果需要支持修改属性,需要额外定义对应属性的setter方法,方法名和@property装饰的方法名一致,装饰器为@方法名.setter。
class User:
def __init__(self, name, age):
self._name = name
self._age = age
@property
def age(self):
# age属性的getter方法
return self._age
@age.setter
def age(self, value):
# age属性的setter方法,在这里可以添加校验逻辑
if not isinstance(value, int):
raise TypeError("年龄必须是整数")
if value < 0 or value > 150:
raise ValueError("年龄必须在0到150之间")
self._age = value
# 创建实例
user = User("张三", 20)
print(user.age) # 输出:20
# 合法修改
user.age = 25
print(user.age) # 输出:25
# 非法修改会抛出对应异常
# user.age = -5 # 抛出ValueError: 年龄必须在0到150之间
# user.age = "二十" # 抛出TypeError: 年龄必须是整数
定义可删除的属性
如果需要支持删除属性,可以再定义deleter方法,装饰器为@方法名.deleter。
class User:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError("姓名必须是字符串")
self._name = value
@name.deleter
def name(self):
# 删除属性时的逻辑,这里示例是将内部属性设为None
print("删除姓名属性")
self._name = None
user = User("张三")
print(user.name) # 输出:张三
del user.name # 输出:删除姓名属性
print(user.name) # 输出:None
使用@property保护属性的实际场景
在实际开发中,@property最常见的用途就是对属性的赋值进行合法性校验,避免外部传入不符合要求的数据,下面是几个常见的场景示例。
场景1:限制属性取值范围
比如一个学生类,成绩属性只能在0到100之间,通过@property的setter方法就可以实现这个限制。
class Student:
def __init__(self, score):
self._score = score
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, (int, float)):
raise TypeError("成绩必须是数字")
if value < 0 or value > 100:
raise ValueError("成绩必须在0到100之间")
self._score = value
stu = Student(85)
print(stu.score) # 输出:85
stu.score = 92.5
print(stu.score) # 输出:92.5
# stu.score = 101 # 抛出ValueError: 成绩必须在0到100之间
场景2:计算属性
有些属性不需要单独存储,而是通过其他属性计算得到的,也可以用@property来实现,比如矩形的面积和周长,不需要单独存,通过长和宽计算即可。
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
@property
def area(self):
# 面积属性,由长和宽计算得到,不需要单独存储
return self.length * self.width
@property
def perimeter(self):
# 周长属性,由长和宽计算得到
return 2 * (self.length + self.width)
rect = Rectangle(5, 3)
print(rect.area) # 输出:15
print(rect.perimeter) # 输出:16
# 修改长和宽后,面积和周长会自动更新
rect.length = 10
print(rect.area) # 输出:30
注意事项
- 使用@property装饰的方法名不要和内部存储的属性名完全一致,通常内部属性用下划线开头,比如内部存为_age,装饰的方法名为age,避免递归调用导致栈溢出。
- 如果只定义了@property的getter方法,没有定义setter方法,那么该属性就是只读的,外部尝试修改会抛出AttributeError。
- @property装饰器是Python的语法糖,本质是将方法转换为描述符对象,理解描述符的原理可以更深刻地掌握它的工作机制,不过日常使用只需要掌握上述用法即可。
通过合理使用@property装饰器,我们可以让类的属性访问更加直观,同时有效保护属性的合法性,是Python面向对象编程中非常重要的一个工具。
Pythonproperty装饰器属性保护面向对象编程getter_setter修改时间:2026-06-26 15:48:24