python - 为什么 hasattr 在使用 @property 方法的类和实例上表现不同?
问题描述
我在我的班级中实现了一个只写@property
属性。奇怪的是,hasattr
具有此属性的类和相应实例的行为不同。
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(Base, UserMixin):
# codes omitted...
@property
def password(self):
raise AttributeError("password is a write-only attribute!")
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def verify_password(self, password):
return check_password_hash(self.password_hash, password)
In [6]: hasattr(User,'password')
Out[6]: True
In [7]: u1=User()
In [9]: hasattr(u1,'password')
Out[9]: False
In [12]: getattr(User,'password')
Out[12]: <property at 0x1118a84a8>
In [13]: getattr(u1,'password')
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-13-b1bb8901adc7> in <module>
----> 1 getattr(u1,'password')
~/workspace/python/flask_web_development/fisher/app/models.py in password(self)
82 @property
83 def password(self):
---> 84 raise AttributeError("password is a write-only attribute!")
85
86 @password.setter
AttributeError: password is a write-only attribute!
从 的结果来看getattr
,getattr(u1, 'password')
尝试执行该方法并引发错误,而getattr(User, 'password')
没有执行该@property
方法。为什么他们的行为不同?
解决方案
属性是描述符。
关于getattr
:
当您通过对象 ( )getattr
或点符号访问属性并且该对象 ( u1
) 的类User
恰好有一个描述符,该描述符以您尝试访问的名称命名时,该描述符的__get__
方法称为1,当您问题getattr(u1, 'password')
。在您的特定情况下,您在 getter 中定义的逻辑(提高AttributeError
)将被执行。
将getattr(User, 'password')
实例传递给__get__
方法 is None
,在这种情况下,__get__
只返回描述符本身,而不是执行您实现的 getter 逻辑。
1有一些特殊规则,具体取决于您是否拥有数据或非数据描述符,如 Descriptor HowTo 中所述。
关于hasattr
:
hasattr(u1, 'password')
返回False
,因为getattr(u1, 'password')
引发错误。看到这个问题。
推荐阅读
- java - 我的应用无法安装在 Marshmallow 及以下版本的手机中
- r - bookdown中如何使用Rscript命令行工具建书
- apache-spark - 如何在谷歌云数据处理集群上同时使用 jupyter、pyspark 和 cassandra
- session - 如何用字符串扩展 session.Value
- sql - SQL:寻找舍入重复
- javascript - 获取动态创建元素(Javascript,DOM)的CSS宽度
- templates - 检查符号是 D 中的 [pointer to] 成员函数/字段
- java - 使用 livedata 压缩 4 个或更多异步调用
- ms-access - ms 访问如何运行减法而不是运行加法
- ruby - '.' 之间的区别 和 RUBY 中的 File.dirname(__FILE__)