Python中何时结合getter、setter使用@property?是否符合Pythonic开发规范?
问题1:什么时候应该搭配getter、setter使用@property装饰器?
适合使用@property的场景主要有这几类:
- 你需要给属性增加读写校验、动态计算逻辑,但又想保留属性的简洁访问方式(比如还是用
person.age = 20赋值,而不是调用person.set_age(20)),对调用方更友好 - 历史代码已经对外暴露了公开属性,后续迭代需要增加属性的读写控制逻辑,用
@property可以完全兼容原有调用代码,不需要修改调用侧的逻辑 - 属性本身是动态生成的,不需要额外存储,比如根据
firstname和lastname计算fullname,不需要额外存一个fullname字段,用@property可以在访问时自动计算
问题2:不使用@property来实现getter、setter是否不符合Pythonic规范,属于错误实现?
这完全不是错误实现,也不能说不符合Pythonic规范,只是适用场景不同:
- 普通get/set方法有自己的优势:支持传入额外参数,比如
set_age(20, skip_check=True)可以加跳过校验的参数,这是@property的setter做不到的(setter只能接收一个赋值参数) - 如果你的项目有跨语言对齐需求,比如团队之前是Java技术栈,或者接口要和其他语言的服务统一字段访问方式,用普通get/set完全合理
- 注意你给出的示例2存在bug:
get_age直接返回self.age、set_age直接赋值self.age会触发无限递归,实际写的时候要把存储的属性改成私有属性self._age才行。
问题3:日常开发中是否应当优先选择@property的写法?
绝大多数普通场景下优先用@property就好,写法更简洁,也符合Python的统一访问原则。但不要滥用:
- 如果属性的读写逻辑很重(比如要访问数据库、调用外部接口),就不要用
@property,大家的普遍认知是属性访问是轻量、无副作用的,把重逻辑藏在属性里会给调用方造成误导 - 如果读写逻辑需要额外参数,直接写普通get/set方法更合适
以下是修正了语法错误的两种实现示例:
示例1:使用@property实现
class Person: def __init__(self, firstname, lastname, age): self.firstname = firstname self.lastname = lastname self.age = age def say_hi(self): print(f"Hi i'm {self.firstname} {self.lastname} and i'm {self.age}") @property def age(self): return self._age @age.setter def age(self, newage): if not isinstance(newage, int): raise TypeError("Expect an Integer") self._age = newage
示例2:使用普通get、set方法实现
class Person2: def __init__(self, firstname, lastname, age): self.firstname = firstname self.lastname = lastname self.set_age(age) def say_hi(self): print(f"Hi i'm {self.firstname} {self.lastname} and i'm {self.get_age()}") def get_age(self): return self._age def set_age(self, newage, skip_check=False): # 普通set方法支持额外参数扩展 if not skip_check and not isinstance(newage, int): raise TypeError("Expect an Integer") self._age = newage
内容的提问来源于stack exchange,提问作者kjay
相关产品推荐
相关产品推荐

