почему глобальная переменная __metaclass__ не работает? - PullRequest
0 голосов
/ 09 мая 2019

Я определю здесь некоторую функцию, она изменит все пользовательские атрибуты в верхний регистр

def up(name, parent, attr):
    user_defined_attr = ((k, v) for k, v in attr.items() if not k.startswith('_'))
    up_attr = {k.upper(): v for k,v in user_defined_attr}
    return type(name, parent, up_attr)

Например:

my_class = up('my_class', (object,), {'some_attr': 'some_value'})

hasattr(my_class, 'SOME_ATTR')
True

Вот несколько слов из документа Python о metaclass

https://docs.python.org/2/reference/datamodel.html?highlight=metaclass#metaclass

The appropriate metaclass is determined by the following precedence rules:

If dict['__metaclass__'] exists, it is used.
Otherwise, if there is at least one base class, its metaclass is used (this looks for a __class__ attribute first and if not found, uses its type).
Otherwise, if a global variable named __metaclass__ exists, it is used.
Otherwise, the old-style, classic metaclass (types.ClassType) is used.

Итак, я провел некоторый тест

>>> def up(name, parent, attr):
...     user_defined_attr = ((k, v) for k, v in attr.items() if not k.startswith('_'))
...     up_attr = {k.upper(): v for k,v in user_defined_attr}
...     return type(name, parent, up_attr)
... 
>>> 
>>> 
>>> __metaclass__ = up
>>> 
>>> class C1(object):
...     attr1 = 1
... 
>>> hasattr(C1, 'ATTR1')
False

Не работает для глобального случая var, почему?

Ответы [ 2 ]

1 голос
/ 09 мая 2019

Кажется, что только классы старого стиля используют глобальную переменную __metaclass__.Тот факт, что они в старом стиле, не имеет к этому никакого отношения, но именно так они определены.Классы нового стиля явно наследуются от класса с мета-классом, тогда как классы старого стиля этого не делают.

class Meta(type):
    pass


__metaclass__ = Meta


class NewStyle(object):
    pass

class OldStyle:
    pass


print "new style", type(NewStyle)
print "old style", type(OldStyle)

Этот код печатает:

new style <type 'type'>
old style <class '__main__.Meta'>

Кажется, это соответствуетс правилами, которые вы перечислили.У NewStyle есть базовый класс object, и у этого класса есть собственный метакласс type.Таким образом, для классов нового стиля type выбирается в соответствии с правилом секунд.

1 голос
/ 09 мая 2019

Если вы работаете на Python 2, ваша проблема в том, что вы перечислили object в качестве базового класса для C1, а глобальный резервный __metaclass__ имеет более низкий приоритет, чем метакласс базового класса.

Если вы используете Python 3, ваша проблема в том, что глобальный __metaclass__ больше ничего не делает.

...