python - 使用数据描述符访问 python 属性
问题描述
我已经阅读了一些访问实例属性时的博客和文档obj.a
:
a
尝试访问当前类和基类 __dict__中的数据描述符(命名)__dict__
- 找到
a
_obj.__dict__
a
在当前类__dict__
和基类中查找非数据描述符(命名)__dict__
a
在当前类__dict__
和基类中查找属性(命名)__dict__
__getattr__
如果有的话打电话- 增加
AttributeError
但我发现此搜索规则与以下代码的行为不匹配:
class ADesc(object):
def __init__(self, name):
self._name = name
def __get__(self, obj, objclass):
print('get.....')
return self._name + ' ' + str(obj) + ' ' + str(objclass)
def __set__(self, obj, value):
print('set.....')
self._name = value
class A(object):
dd_1 = ADesc('dd_1 in A')
class B(A):
dd_1 = 'dd_1 in B'
if __name__ == '__main__':
print(A.__dict__)
# {'dd_1': <__main__.ADesc object at 0x10ed0d050>, '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
print(B.__dict__)
# {'dd_1': 'dd_1 in B', '__module__': '__main__', '__doc__': None}
b = B()
print(b.dd_1) # dd_1 in B
我认为最后一个print(b.dd_1)
将调用__get__
in ADesc
,因为根据第一条规则,__dict__
基类A
包含我们正在访问的属性dd_1
,因此应该调用数据描述符。那么上面的访问规则是错误的还是这里涉及的任何其他魔法?
解决方案
您误解了如何在类中找到描述符。Python 将使用类层次结构中的第一个这样的名称。一旦找到,搜索就会停止。B.dd_1
存在,所以A.dd_1
不考虑。
B
该文档告诉您关于未定义的情况的基类dd_1
;在这种情况下B
,搜索,然后A
。但是当B
有一个属性时dd_1
,任何进一步的搜索都会停止。
请注意,搜索顺序由 MRO 类(方法解析顺序)设置。而不是区分类中的搜索__dict__
和基类的__dict__
属性,您应该将搜索视为:
def find_class_attribute(cls, name):
for c in cls.__mro__:
if name in c.__dict__:
return c.__dict__[name]
MRO(由cls.__mro__
属性体现)包括当前类对象:
>>> B.__mro__()
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
相关文档可在数据模型参考中找到;自定义类指出:
类属性引用被翻译成这个字典中的查找,例如,
C.x
被翻译成C.__dict__["x"]
(尽管有许多钩子允许其他定位属性的方法)。如果在那里找不到属性名称,则在基类中继续进行属性搜索。
实例属性的实际实现是这样的:
- 班级位于 (
type(instance)
) - 类
__getattribute__
方法称为 (type(instance).__getattribute__(instance, name)
) __getattribute__
扫描 MRO 以查看该名称是否存在于该类及其基类 (find_class_attribute(self, name)
)- 如果存在这样的对象,并且它是一个数据描述符(具有
__set__
or__delete__
方法),则使用该对象,并且停止搜索。 - 如果存在这样的对象但它不是数据描述符,则保留参考以供以后使用。
- 如果存在这样的对象,并且它是一个数据描述符(具有
__getattribute__
在中查找名称instance.__dict__
- 如果有这样的对象,搜索就会停止。使用实例属性。
- 没有找到数据描述符,并且实例字典中没有属性。但是通过 MRO 的搜索可能已经找到了一个非数据描述符对象
- 如果在 MRO 中找到对对象的引用,则使用该对象并停止搜索。
- 如果
__getattr__
在类(或基类)上定义了方法,则调用它,并使用结果。搜索停止。 - an
AttributeError
被提出。
推荐阅读
- swift - 如果我们在 Parchment 的 HeaderExample 中替换 UIView 而不是 UIImageView,则渐变背景不起作用
- computer-vision - 图像的一类分类
- python-3.x - 将 Sublime Text 与 Anaconda 一起使用的 Numpy ImportError
- ios - 如何修复通过firebase收到的用于react-native的苹果推送通知
- javascript - 获取 SCRIPT5009:Internet Explorer IE 11 中未定义“id”
- sql-server - SSIS 事件处理程序
- angular - 在 Angular 应用程序的控制台中出现“对象(...)不是函数”错误
- laravel - Eloquent 返回同一模型的多个实例
- codenameone - 如何生成代号一的二维码
- apache - Docker 容器不再允许 Web 访问