методы метаклассов на экземплярах класса

Я задавался вопросом, что происходит с методами, объявленными на метаклассе. Я ожидал, что, если Вы объявляете метод на метаклассе, он закончит тем, что был classmethod, однако, поведение отличается. Пример

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print "foo"
... 
>>> a=A()
>>> a.foo()
foo
>>> A.foo()
foo

Однако, если я пытаюсь определить метакласс и дать ему нечто метода, это, кажется, работает то же на класс, не на экземпляр.

>>> class Meta(type): 
...     def foo(self): 
...         print "foo"
... 
>>> class A(object):
...     __metaclass__=Meta
...     def __init__(self):
...         print "hello"
... 
>>> 
>>> a=A()
hello
>>> A.foo()
foo
>>> a.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'foo'

Что продолжается здесь точно?

править: столкновение вопроса

11
задан Stefano Borini 11 February 2010 в 16:07
поделиться

3 ответа

Вы подняли хорошую тему.

Вот хорошая ссылкадля лучшего понимания отношений между объектами, классами и метаклассами:

Я также нахожу эту ссылку по дескрипторам весьма познавательной в отношении механизма поиска в python.

Но я не могу сказать, что понимаю, почему a.foo не работает, когда A.foo работает. Похоже, что когда вы ищете атрибут объекта, а python не находит его там, он не совсем ищет атрибут в классе, потому что если бы он это сделал, то нашел бы A.foo.

EDIT:

О! Кажется, я понял. Это связано с тем, как работает наследование. Если рассмотреть схему, приведенную по ссылке выше, то она выглядит так:

alt text

Схематично это сводится к следующему:

type -- object
  |       |
Meta --   A  -- a

Переход влево означает переход к классу данного экземпляра. Переход вверх означает переход к родителю.

Теперь механизм наследования заставляет механизм поиска сделать поворот направо в схеме выше. Он переходит к a → A → object. Он должен сделать это, чтобы следовать правилу наследования! Чтобы было понятно, путь поиска таков:

 object
   ^
   |
   A  <-- a

Тогда, очевидно, атрибут foo не будет найден.

Когда вы ищете атрибут foo в A, однако, он находится, потому что путь поиска:

type
  ^
  |       
Meta <--   A 

Все это имеет смысл, если вспомнить, как работает наследование.

15
ответ дан 3 December 2019 в 04:32
поделиться

Как я понимаю заключается в том, что Meta - это класс, а A - его экземпляр. Таким образом, когда вы вызываете A.foo (), он проверяет объект и его класс. Итак, при попытке A.foo он сначала просматривает методы A сам, а затем методы своего класса Meta. Поскольку A не содержит самого метода foo, он использует метод Meta, и поэтому действительно выполняет Meta.foo (A).

Аналогичным образом, когда a.foo пробуется , он сначала просматривает A. Поскольку a не содержит метода foo, он будет просматривать A. Но A также не содержит метода foo, поскольку foo хранится в Meta. Поскольку ни a, ни A не содержат foo, это вызовет AttributeError.

Я пробовал это остроумие h переменная, а также функция, помещая в класс Meta атрибут txt = 'txt', и это также было доступно для A, но не для a. Итак, я склонен думать, что я прав в своем понимании, но я просто догадываюсь.

0
ответ дан 3 December 2019 в 04:32
поделиться

Правило таково: при поиске атрибута объекта учитывается класс объекта и его родительские классы. Метакласс класса объекта, однако, не учитывается. Когда вы обращаетесь к атрибуту класса, класс класса является метаклассом, поэтому он учитывается. Возврат от объекта к его классу не вызывает "нормального" поиска атрибута в классе: например, дескрипторы вызываются по-разному, если доступ к атрибуту осуществляется в экземпляре или в его классе.

Методы - это атрибуты, которые могут быть вызваны (и имеют метод __get__, который заставляет автоматически передавать 'self'). Это делает так, что методы на метаклассе подобны методам класса, если вы вызываете их на классе, но не доступны на экземпляре.

9
ответ дан 3 December 2019 в 04:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: