Python 为什么hasattr在使用@property方法的类和实例上表现不同?
我用Python 为什么hasattr在使用@property方法的类和实例上表现不同?,python,python-decorators,readonly-attribute,writeonly,Python,Python Decorators,Readonly Attribute,Writeonly,我用@property在类中实现了一个只写属性。奇怪的是,hasattr在具有此属性的类和相应实例上的行为不同 从werkzeug.security导入生成\u密码\u散列,检查\u密码\u散列 从flask_登录导入UserMixin 类用户(Base,UserMixin): #代码省略。。。 @财产 def密码(自我): raise AttributeError(“密码是只写属性!”) @密码设置器 def密码(self,password): self.password\u hash=生成密
@property
在类中实现了一个只写属性。奇怪的是,hasattr
在具有此属性的类和相应实例上的行为不同
从werkzeug.security导入生成\u密码\u散列,检查\u密码\u散列
从flask_登录导入UserMixin
类用户(Base,UserMixin):
#代码省略。。。
@财产
def密码(自我):
raise AttributeError(“密码是只写属性!”)
@密码设置器
def密码(self,password):
self.password\u hash=生成密码\u hash(密码)
def验证_密码(自我、密码):
返回检查\u密码\u散列(self.password\u散列,password)
[6]中的:hasattr(用户,'password')
Out[6]:对
在[7]中:u1=User()
[9]中的hasattr(u1,'password')
Out[9]:假
在[12]中:getattr(用户,'password')
出[12]:
在[13]中:getattr(u1,'password')
---------------------------------------------------------------------------
AttributeError回溯(最近一次呼叫上次)
在里面
---->1 getattr(u1,'password')
密码中的~/workspace/python/flask\u web\u development/fisher/app/models.py(self)
82@property
83 def密码(自我):
--->84 raise AttributeError(“密码是只写属性!”)
85
86@password.setter
AttributeError:密码是一个只写属性!
根据getattr
的结果,getattr(u1,'password')
尝试执行该方法并引发错误,而getattr(User,'password')
不执行@property
方法。为什么它们的行为会有所不同?属性是不同的
关于
getattr
:
当您通过对象(u1
)上的点符号(getattr
)或该对象的类(User
)访问属性时,恰好有一个描述符以您试图访问的名称命名,该描述符的\uu get\uuu
方法被调用1,就像您发出getattr(u1,'password')时一样
。在您的特定情况下,将执行在getter中定义的逻辑(提高AttributeError
)
使用getattr(User,'password')
传递给\uuu get\uuu
方法的实例是None
,在这种情况下\uu get\uu
只返回描述符本身,而不是执行您实现的getter逻辑
1以下是一些特殊规则,具体取决于您是否拥有数据描述符或非数据描述符,如描述符HowTo中所述
关于hasattr:
hasattr(u1,'password')
返回False
,因为getattr(u1,'password')
引发错误。参见问题。除了@timgeb提到的内容之外,还有很多事情发生在背景中,而不是出现在背景中
属性作为描述符实现,当您使用对象
和类
访问属性时,属性查找的方式不同。当您使用对象(如obj.attr
访问属性时,基本上属性查找规则如下
\uuuu class\uuuuuu.\uuuuu dict\uuuuuuu
并查看此属性是否是数据描述符,如果是,则调用\uuuu get\uuuuuuuu
,这将转换为类型(obj)。\uuuuuu dict\uuuuu['attr'.\uu get\uuj(obj,type(obj))
\uuuu dict\uuuu
并返回obj.\uu dict\uuuu['attr']
\uuuuu get\uuuuu
,这再次转换为类型(obj)。\uuuu dict\uuuu['attr'].\uuu get\uuj(obj,类型(obj))
\uuuu dict\uuu
获取属性getattr
的默认实现class.attr
访问同一属性时,同样的规则也适用,但有一点不同,这一次还涉及类的元类
,因此看起来是这样的
type(class)。\uuuuu dict\uuuuu['attr']\uuuuu get\uuuu(class,type(class))
\uuuuuuuuuuuuuuuuu
内部,查看此属性是否为任何类型的描述符,如果是,则获取调用\uuuuuuuuu get\uuuuuuuuuu
的属性,如果不是描述符,则从类的\uuuuuuuuuuuuuuuuuu
获取值\uuuu get\uuuu
\uuuu dict\uuu
获取属性getattr
的默认实现李>
此外,属性的\uuuuu get\uuuu
的默认实现有一个检查,即当您使用类访问属性时,它返回描述符实例本身,但是当您使用对象访问属性时,它实际上会在\uuuu get\uu
中触发代码
def __get__(self, instnace, class):
if instance is None:
return self
else:
# code
这也解释了为什么
hasattr(用户,'password')
返回True
,因为您使用类调用属性,else
不会执行,因此不会引发exception
并且hasattr(u1,'password'))
在遇到异常时返回False
。您是在询问hasattr
还是getattr
?当您在类上获取实际对象时getattr
,只有在实例上调用getattr
时,才会调用它的\uuuu get\uuuu
方法。另请参见,例如,这是只读的,而不是只读的。getattr(用户“密码”)
会进行描述符处理property
只是实现处理,它做的事情与它不是该情况的描述符一样。(更明显的是