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很困惑。
答案 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__
不会传递给实际的类创建过程)