python __metaclass__不起作用

时间:2018-08-16 14:17:05

标签: python metaclass

   class UpperAttrMetaClass(type):
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return type.__new__(upperattr_metaclass,future_class_name, future_class_parents, uppercase_attr)



class boo(object):
    __metaclass__ = UpperAttrMetaClass
    bar = 'birr'


print(hasattr(boo,'BAR'))

我的目标是使用 metaclass 将类boo的名为'bar'的属性转换为大写的'BAR',但是程序的结果为'False',表明它不起作用,i很困惑。

1 个答案:

答案 0 :(得分:0)

该代码在某种程度上是错误的,它以__开头的所有方法或属性都被过滤掉了,并且没有加回来。但这不会阻止它正确地大写您的其他属性。

因此,可能发生的情况是您正在将它与Python 3配合使用,并对元类使用Python 2语法,这在类主体中添加了__metaclass__属性。

如果您仅将creatin类更改为Python 3,它将起作用:

class boo(metaclass=UpperAttrMetaclass):
    ...

除此之外,您正在过滤掉可以在类主体中定义的所有魔术名称-因此__init__,所有其他特殊方法,甚至__slots__都将被排除在实际类之外。如果不是您的意图,则必须更改它-您可以在一行中进行过滤和大写:

def __new__(mcls, name, bases, namespace):
    namespace = {(name.upper() if not name.startswith('__') else name)  : value for namespace.__items__()}
    return super().__new__(mcls, name, bases, namespace)

我使用了您的算法,但是请注意,以__开头但不是结尾的实际非魔术属性将被处理并大写:将类名称添加到此类属性的名称修饰发生在编译时,在调用任何metclass方法之前(甚至在将元类的__prepare__返回的命名空间中设置项目之前))。因此,如果要跳过诸如__name之类的属性,则应检查if '__' not in name

(也请注意,这是显式的Python 3)。

此外,为了确保上面提到的名称改名声明先于其他内容,我在终端中进行了一次小测试。由于这是一个很好的示例,因此,我粘贴了此测试波纹管,以便将其记录在案的其他用户中查找相关问题:

class M(type):
    def __prepare__(self, name):
        class N(dict):
            def __setitem__(self, item, value):
                print(item)
                super().__setitem__(item, value)
        return N()
    def __new__(mcls, name, bases, ns):
        print(ns)
        return super().__new__(mcls, name, bases, ns)


class A(metaclass=M):
    __hidden = 0

在创建A时的输出:

__module__
__qualname__
_A__hidden
{'__module__': '__main__', '__qualname__': 'A', '_A__hidden': 0}

(请注意,在您的代码中,__module____qualname__不会传递给实际的类创建过程)