一,使用函数实现
def upper_attr(class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith('__'):
new_attr[name.upper()] = value # 将属性名转为大写后返回给创建的类
return type(class_name, class_parents, new_attr) # 返回创建好的类,type是固定这些参数
# metaclass的定义如果使用函数自定义一个类的实现,如果是函数则调用函数实现,如果是类,则实例化类实现
# 第一种使用函数实现
class Foo(object, metaclass=upper_attr):
bar = 'pop'
f = Foo()
print(f.BAR) #返回的类中属性名已被被处理为大写
二,使用类实现
class UpAttrMetaClass(type): # 这里必须继承与type,否则报错:
# metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
# 元类冲突:派生类的元类必须是其所有基元类的(非严格)子类, 即元类必须是基类的子类,基类自是type
def __new__(cls, class_name, class_parent, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith('__'):
new_attr[name.upper()] = value
# 1, return type(class_name, class_parent, new_attr)
# 2, return type.__new__(cls, class_name, class_parent, new_attr) 调用父类的__new__方法
# return super().__new__(cls, class_name, class_parent, new_attr) 调用父类的__new__方法
return super(UpAttrMetaClass, cls).__new__(cls, class_name, class_parent, new_attr) # 兼容py2
class Foo(object, metaclass=UpAttrMetaClass): # 当使用一个类来自定义生成类(作为元类),会实例化这个类来实现,所以改写类的__new__方法即可
bar = 'pop'
# -- tips ---
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
f = Foo()
print(f.BAR)
基于想要达到的目的(自定义类的创建),元类的主要作用是:
- 拦截类的创建
- 修改类
- 返回修改之后的类
究竟为什么要使用元类?
一般来说,用不上它:
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters