Когда я говорю "процесс поиска атрибутов python", я имею в виду: что делает python, когда вы пишете x.foo??
Поиск в Интернете я не нашел много документов об этом, одна из лучших статей, которые я нашел, возобновил процесс до следующих шагов (вы можете увидеть полную статью здесь)
- Если attrname является специальным (то есть Python-предоставленным) атрибутом для objectname, верните его.
- Проверить имя объекта.__ class __.__ dict__ для attrname. Если он существует и является дескриптором данных, верните результат дескриптора. Поиск всех оснований objectname.__ class__ для одного и того же случая.
- Проверьте имя объекта.__ dict__ для имени attrname и верните, если он найден. Если objectname является классом, ищите его базы тоже. Если это класс и существует дескриптор в нем или его основаниях, верните результат дескриптора.
- Проверить имя объекта.__ class __.__ dict__ для attrname. Если он существует и является дескриптором без данных, верните результат дескриптора. Если он существует и не является дескриптором, просто верните его. Если он существует и является дескриптором данных, мы не должны быть здесь, потому что мы вернемся в точке 2. Найдите все базы objectname.__ class__ для одного и того же случая.
- Raise AttributeError.
Сначала это может показаться правильным, но процесс поиска атрибутов немного сложнее, например, для x.foo, он не ведет себя одинаково, если x является классом или экземпляром.
У меня есть несколько примеров, которые невозможно объяснить этим способом. Рассмотрим следующий код python:
class Meta(type):
def __getattribute__(self, name):
print("Metaclass getattribute invoked:", self)
return type.__getattribute__(self, name)
def __getattr__(self, item):
print('Metaclass getattr invoked: ', item)
return None
class C(object, metaclass=Meta):
def __getattribute__(self, name):
print("Class getattribute invoked:", args)
return object.__getattribute__(self, name)
c=C()
Теперь проверьте следующие строки с соответствующим выходом:
>> C.__new__
Metaclass getattribute invoked: <class '__main__.C'>
<built-in method __new__ of type object at 0x1E1B80B0>
>> C.__getattribute__
Metaclass getattribute invoked: <class '__main__.C'>
<function __getattribute__ at 0x01457F18>
>> C.xyz
Metaclass getattribute invoked: <class '__main__.C'>
Metaclass getattr invoked: xyz
None
>> c.__new__
Class getattribute invoked: (<__main__.C object at 0x013E7550>, '__new__')
<built-in method __new__ of type object at 0x1E1B80B0>
>> c.__getattribute__
Class getattribute invoked: (<__main__.C object at 0x01438DB0>, '__getattribute__')
Metaclass getattribute invoked: <class '__main__.C'>
<bound method C.__getattribute__ of <__main__.C object at 0x01438DB0>>
>>
Выводы, которые я сделал (учитывая, что мы ищем x.foo):
- __ getattribute__ отличается для экземпляров < тип 'type' > и < type 'object' > . Для C.foo(), "foo" выполняется поиск сначала на C.__ dict__ и возвращается, если найден (вместо поиска типа (C)), а для x.foo() 'foo' выполняется поиск по типу (x).__ dict__ и на x.__ dict __.
- __ Метод getattribute__ всегда разрешен по типу (x), что я не понимаю здесь, это последний случай: c.__ getattribute__, is not object содержит метод __getattribute__ (и C наследует от объекта), так почему метакласс Получается метод getattribute.
Может кто-нибудь объяснить это, пожалуйста? или меньше расскажите мне, где я могу найти документацию об этом, спасибо.