Python中@property装饰器使用时__init__内赋值的相关疑问
关于Python @property装饰器的疑问解答
先看你写的示例代码:
class sample(object): def __init__(self,a): self.x=a # 为何此赋值是必需的?我去掉它就运行失败 @property def x(self): print "getter" return self.__x @x.setter def x(self,a): print "setter" if a<=100 and a>=0: self.__x=a elif a<0: self.__x=0 else: self.__x=100 ob=sample(30) print ob.x
问题1:为何__init__里的self.x=a是必需的?
这得从@property的工作逻辑说起:你定义的x是一个属性访问器,背后依赖私有变量self.__x存储实际值。当你写self.x=a时,并不是直接给某个实例变量赋值,而是调用了被@x.setter装饰的setter方法——这个方法会帮你把符合规则的值存入self.__x。
如果去掉这行代码,创建实例后调用print ob.x时,getter方法会尝试返回self.__x,但此时__x根本没被初始化过,Python就会抛出AttributeError,提示找不到这个属性。
当然,你也可以直接在__init__里写self.__x=a,但这样会跳过setter里的数值校验逻辑——比如传入a=-50的话,直接赋值会让__x变成-50,但通过self.x=a调用setter,会自动把它修正为0。所以用self.x=a才是符合封装思想的正确写法,能复用已有的校验规则。
问题2:公开的'x'有何意义?它是类的成员吗?类仅拥有私有变量__x?
首先明确:这个x不是普通的实例变量,它是一个类级别的描述符(descriptor),由@property和@x.setter共同创建。它的核心意义在于封装:
- 对外提供统一的访问接口
x,使用者不需要关心内部是用__x存储的,哪怕以后你把内部存储换成别的变量名,只要保持x的接口不变,外部代码完全不用修改。 - 可以在getter/setter里添加逻辑(比如你的数值校验、打印日志),而外部调用方式和直接访问普通变量完全一样——这就是@property的“语法糖”优势,让封装变得更优雅。
从实例的角度看,你的sample实例里只有私有变量__x,并没有x这个实例变量。当你执行ob.x或者ob.x=xxx时,Python会通过描述器机制自动调用对应的getter或setter方法,而不是直接操作某个实例属性。
内容的提问来源于stack exchange,提问作者syam
相关产品推荐
相关产品推荐

