Как написать собственный метакласс? - PullRequest
0 голосов
/ 28 февраля 2020

Как создать метакласс в python? Я пытался написать как в учебниках:

class Meta(type):

    def __new__(mcs, name, bases, attrs):
        attrs2 = {'field2': 'Test'}
        attrs2.update(attrs)
        return super(Meta, mcs).__new__(mcs, name, bases, attrs2)


class Test(object):
    __metaclass__ = Meta

    field1 = 10


test = Test()

print(test.field1)
print(test.field2)

Но этот код завершается ошибкой:

10                                                                                                                                                                                 
Traceback (most recent call last):                                                                                                                                                 
  File "main.py", line 18, in <module>                                                                                                                                             
    print(test.field2)                                                                                                                                                             
AttributeError: 'Test' object has no attribute 'field2'  

Как правильно объявить метакласс в python 3.7+?

ОБНОВЛЕНО Я изменил свой вопрос с фактической ошибкой.

1 Ответ

2 голосов
/ 28 февраля 2020

Учебники, которые вы проверяете, охватывают Python 2.

В Python 3 одно из изменений syntacti c было именно способом объявления метакласса для класса. Вам не нужно изменять код метакласса, просто измените объявление класса на:


class Test(metaclass=Meta):

    field1 = 10

, и оно будет работать.

Итак, вкратце: для метакласса в Python 3, вы должны передать эквивалент «аргумента ключевого слова» в объявлении класса с именем «метакласс». (Кроме того, в Python 3 нет необходимости явно наследовать от объекта)

В Python 2 это было достигнуто благодаря наличию специальной переменной __metaclass__ в теле класса , как в вашем примере. (Кроме того, при установке метакласса наследование от «объекта» будет необязательным, поскольку метакласс, производный от типа, сделает это за вас).

Одним из основных преимуществ нового синтаксиса является то, что он разрешает специальный метод __prepare__ в метаклассе, который может возвращать объект пользовательского пространства имен, который будет использоваться при построении самого тела класса. Он редко используется, и действительно «серьезный» вариант использования будет трудно вынести сегодня. Для игрушек и игр - это здорово, учитывая «перечисления magi c autonamed» и другие вещи - но при проектировании Python 3 они думали, что позволят иметь OrderedDict в качестве пространства имен класса, поэтому чтобы методы метакласса __new__ и __init__ могли знать порядок объявления атрибутов. Начиная с Python 3.6, пространство имен тела класса упорядочено по умолчанию, и нет необходимости в методе __prepare__ для одного только этого использования.

...