get_dict_attr
(ниже) ищет attr
в данном объекте __dict__
и возвращает соответствующее значение, если оно есть. Если attr
не является ключом в __dict__
, выполняется поиск MRO __dict__
объекта. Если ключ не найден, AttributeError
поднимается.
def get_dict_attr(obj, attr):
for obj in [obj] + obj.__class__.mro():
if attr in obj.__dict__:
return obj.__dict__[attr]
raise AttributeError
Например,
class Foo(object):
x=1
def bar(self):
pass
@property
def baz(self):
return 0
foo=Foo()
print(get_dict_attr(foo,'x'))
# 1
print(get_dict_attr(foo,'bar'))
# <unbound method Foo.bar>
print(get_dict_attr(foo,'baz'))
# <property object at 0xb77c0dc4>
print(get_dict_attr(foo,'y'))
# AttributeError
Обратите внимание, что это сильно отличается от обычных правил поиска атрибутов.
С одной стороны, дескрипторы данных в obj.__class__.__dict__
(дескрипторы с методами __get__
и __set__
) обычно имеют приоритет над значениями в obj.__dict__
. В get_dict_attr
, obj.__dict__
имеет приоритет.
get_dict_attr
не пытается позвонить __getattr__
.
Наконец, get_dict_attr
будет работать только с объектами obj
, которые являются экземплярами классов нового стиля.
Тем не менее, я надеюсь, что это поможет.
class Foo(object):
@property
def bar(self):
return 0
f = Foo()
Ссылка на свойство bar
:
print(Foo.bar)
# <property object at 0xb76d1d9c>
Вы видите, bar
- это ключ Foo.__dict__
:
print(Foo.__dict__['bar'])
# <property object at 0xb775dbbc>
Все свойства являются дескрипторами, что предполагает использование метода __get__
:
print(Foo.bar.__get__)
# <method-wrapper '__get__' of property object at 0xb76d7d74>
Вы можете вызвать метод, передав объект f
и класс f
в качестве аргументов:
print(Foo.bar.__get__(f,Foo))
# 0
Мне нравится следующая диаграмма. Вертикальные линии показывают связь между объектом и классом объекта.
Если у вас есть такая ситуация:
Foo B
| Foo.__dict__={'bar':b} | B.__dict__={'__get__':...}
| \ |
f `--------> b
f.bar
вызывает b.__get__(f,Foo)
для вызова.
Это подробно объясняется здесь .