Почему класс обращается к переменным из своего метакласса при вызове класса __init__? [закрыто]

Если у вас есть базовый класс A и производный класс B, вы можете сделать следующее.

void wantAnA(A myA)
{
   // work with myA
}

B derived;
// work with the object "derived"
wantAnA(derived);

Теперь для метода wantAnA нужна копия derived , Однако объект derived не может быть полностью скопирован, так как класс B может изобретать дополнительные переменные-члены, которые не находятся в его базовом классе A.

Поэтому, чтобы вызвать wantAnA, компилятор будет «срезать» все дополнительные члены производного класса. Результатом может быть объект, который вы не хотите создавать, потому что

  • он может быть неполным,
  • ведет себя как объект A (все особые поведения класс B теряется).
3
задан martineau 24 March 2019 в 12:46
поделиться

1 ответ

Непонятно, зачем вам нужен метакласс, , вероятно, нет . Но ради упражнения давайте рассмотрим, что это происходит.

Область действия функции Python определяется следующим образом

locals > closure > globals > builtins

Никогда не будет поиск функции в пространстве имен области, где она была вызвана. Обратите внимание, что в этом случае даже определение MyClass.__init__ не будет работать, так как методы класса должны обращаться к своему пространству имен класса через атрибуты.

class SomeClass:
    foo = 0
    def __init__(self):
        self.foo # works
        foo # raises NameError

В частности, это означает, что ваш метод init найдет fields в теле MyMeta.__new__, что является его закрытием.

Хотя, обратите внимание, что пространство имен класса передается в качестве четвертого аргумента методу MyMeta.__new__, здесь attr. Итак, вы можете найти Myclass.fields в attr['fields'] в MyMeta.__new__.

Пример

class MyMeta(type):
    def __new__(mcs, name, bases, attr):
        fields = {'foo': 0}

        def init(self, **kwargs):
            print('kwargs:', kwargs)
            print('MyMeta.__new__.fields:', fields)
            print('attr["fields"]:', attr['fields'])

        attr['__init__'] = init
        return type.__new__(mcs, name, bases, attr)


class Myclass(metaclass=MyMeta):
    fields = {'bar': 1}


r = {'baz': 2}
c = Myclass(**r)

Выход

kwargs: {'baz': 2}
MyMeta.__new__.fields: {'foo': 0}
attr["fields"]: {'bar': 1}
0
ответ дан Olivier Melançon 24 March 2019 в 12:46
поделиться
Другие вопросы по тегам:

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