Разве __metaclass__ не должен принудительно использовать метакласс в Python? - PullRequest
6 голосов
/ 04 мая 2009

Я пытался узнать о метаклассах в Python. Я понял основную идею, но я не могу активировать механизм. Насколько я понимаю, вы можете указать M как метакласс при создании класса K, установив __metaclass__ в M на глобальном уровне или уровне класса. Чтобы проверить это, я написал следующую программу:

p = print

class M(type):
    def __init__(*args):
        type.__init__(*args)
        print("The rain in Spain")

p(1)
class ClassMeta:
    __metaclass__ = M

p(2)
__metaclass__ = M
class GlobalMeta: pass

p(3)
M('NotMeta2', (), {})

p(4)

Однако, когда я запускаю его, я получаю следующий вывод:

C:\Documents and Settings\Daniel Wong\Desktop>python --version
Python 3.0.1

C:\Documents and Settings\Daniel Wong\Desktop>python meta.py
1
2
3
The rain in Spain
4

Разве я не вижу «Дождь в Испании» после 1 и 2? Что здесь происходит?

Ответы [ 3 ]

13 голосов
/ 04 мая 2009

В Python 3 (который вы используете) метаклассы указываются ключевым параметром в определении класса:

class ClassMeta(metaclass=M):
  pass

Указание свойства класса __metaclass__ или глобальной переменной является старым синтаксисом из Python 2.x и больше не поддерживается. См. Также «Что нового в Python 3» и PEP 2115 .

2 голосов
/ 04 мая 2009

Синтаксис метаклассов изменился на в Python 3.0. Атрибут __metaclass__ больше не является особенным ни на уровне класса, ни на уровне модуля. Чтобы сделать то, что вы пытаетесь сделать, вам нужно указать metaclass в качестве ключевого аргумента для оператора class:

p = print

class M(type):
    def __init__(*args):
        type.__init__(*args)
        print("The rain in Spain")

p(1)
class ClassMeta(metaclass=M): pass

Урожайность:

1
The rain in Spain

Как и следовало ожидать.

2 голосов
/ 04 мая 2009

Это работает так, как вы ожидаете в Python 2.6 (и более ранних версиях), но в 3.0 метаклассы определены по-другому:

class ArgMeta(metaclass=M): ...
...