Подтвердить что ты не робот

Метаклассы python на уровне модуля

Я читаю Что такое метакласс в Python?

и я попытался воспроизвести верхний метакласс из примера и обнаружил, что это не работает во всех случаях:

def upper(cls_name, cls_parents, cls_attr):                                     
    """ Make all class attributes uppper case """                               
    attrs = ((name, value) for name, value in cls_attr.items()                  
            if not name.startswith('__'))                                       
    upper_atts = dict((name.upper(), value) for name, value in attrs)           
    return type(cls_name, cls_parents, upper_atts)                              

__metaclass__ = upper #Module level
class Foo:                                                                      
    bar = 1                                                                     
f =  Foo()
print(f.BAR) #works in python2.6

Вышеупомянутый сбой (с ошибкой атрибута) в python3, который я считаю естественным, потому что все классы в python3 уже имеют объект, поскольку их родительское и метаклассовое разрешение попадают в класс объекта.

Вопрос:

Как создать метакласс уровня модуля в python3?

4b9b3361

Ответ 1

Метакласс уровня модуля на самом деле не является "уровнем модуля", он связан с тем, как работает инициализация класса. Создание класса будет искать переменную "__metaclass__" при создании класса, и если бы она не была в локальной среде, она бы выглядела в глобальном. Следовательно, если бы у вас был "уровень модуля" __metaclass__, который будет использоваться для каждого класса после этого, если у них не было явных метаклассов.

В Python 3 вместо этого вы определяете метакласс с metaclass= в определении класса. Следовательно, метаклассы уровня модуля отсутствуют.

Итак, что вы делаете? Легко: Вы указываете его явно для каждого класса.

Это действительно не так много дополнительной работы, и вы даже можете сделать это с хорошим поиском regexp и заменить, если у вас действительно есть сотни классов и вы не хотите делать это вручную.

Ответ 2

Если вы хотите изменить все атрибуты в верхнем регистре, вы, вероятно, должны использовать метод __init__, чтобы сделать это, чем использовать метакласс.

Метаклассы более глубокие, чем 99% пользователей должны когда-либо беспокоиться. Если вы задаетесь вопросом, нужны ли вам они, вы не делаете (люди, которые действительно нуждаются в них, знают с уверенностью, что они в них нуждаются, и не нуждаются в объяснении о том, почему).

- Python Guru Тим Питерс

Если вам нужно что-то более глубокое, вы также должны оценить с помощью Class Decorators.

Использование MetaClasses и понимание того, как создаются классы, настолько ненужны, пока вы хотите сделать что-то, что вы можете сделать, используя декораторы классов или инициализацию.

Тем не менее, если вы действительно хотите использовать Metaclass tho 'pass, что в качестве аргумента ключевого слова для класса.

class Foo(object, metaclass=UpperCaseMetaClass)

где UpperCaseMetaClass - класс, который расширяет type, а не метод.

class UpperCaseMetaClass(type):
    def __new__():
        #Do your Magic here.