metaclass
)是Python中用于创建类的类。# 使用class关键字创建
class PeaShooter(object):
owner = "戴夫"
def __init__(self, name):
self.name = name
def introduce(self):
print(f"I`m {self.name}")
print(PeaShooter.__dict__)
# {'__module__': '__main__', 'owner': '戴夫', '__init__': , 'introduce': , '__dict__': , '__weakref__': , '__doc__': None}
# 使用type函数创建
# 类名
class_name = "PeaShooter"
# 基类
class_bases = (object,)
# 类的名称空间
class_dict = {}
class_body = """
owner = "戴夫"
def __init__(self, name):
self.name = name
def introduce(self):
print(f"T`m {self.name}")
"""
# 类的属性和方法存储在class_dict里面. 第二个参数{}控制代码的执行环境
exec(class_body, {}, class_dict)
# 使用type函数创建
PeaSHooter = type(class_name, class_bases, class_dict)
print(PeaSHooter.__dict__)
# {'owner': '戴夫', '__init__': , 'introduce': , '__module__': '__main__', '__dict__': , '__weakref__': , '__doc__': None}
metaclass=type
)
type
# 自定义元类
class MyMeta(type):
pass
# 普通的类,元类默认是type
class PeaShooter(object, metaclass=type):
pass
# 普通自定义的类,元类是Shooter
class PeaShooter(object, metaclass=Mymeta):
pass
__new__
、__init__
__new__
:申请空间,创建并返回一个空对象__init__
:接收new创建的空对象,并初始化这个空对象__call__
__call__
:当对象被调用时触发# 类名
class_name = "PeaShooter"
# 类的基类
class_bases = (object, )
# 类的名称空间
class_dict = {}
# 使用元类创建类
PeaShooter1 = type(class_name, class_bases, class_dict)
# 使用自定义元类创建类
class MyMeta(type):
pass
PeaShooter2 = MyMeta(class_name, class_bases, class_dict)
type
是Python的内置元类,而使用type创建类就是通过元类type进行类的实例化过程,即元类的实例化会自动触发魔法方法__init__
、__new__
__init__
、__new__
来控制类名、基类、名称空间这些参数class MyMeta(type):
def __init__(cls, what, bases, dict):
print("自定义元类的魔法方法init")
print(f"参数cls:{cls}")
print(f"参数what:{what}")
print(f"参数bases:{bases}")
print(f"参数dict:{dict}")
super().__init__(what, bases, dict)
def __new__(cls, *args, **kwargs):
print("自定义元类的魔法方法new")
print(f"参数cls:{cls}")
print(f"参数args:{args}")
print(f"参数kwargs:{kwargs}")
return super().__new__(cls, *args, **kwargs)
# 等价于 PeaShooter = MyMeta("PeaShooter", (object, ), {})
class PeaShooter(object, metaclass=MyMeta):
pass
# 自定义元类的魔法方法new
# 参数cls:
# 参数args:('PeaShooter', (,), {'__module__': '__main__', '__qualname__': 'PeaShooter'})
# 参数kwargs:{}
# 自定义元类的魔法方法init
# 参数cls:
# 参数what:PeaShooter
# 参数bases:(,)
# 参数dict:{'__module__': '__main__', '__qualname__': 'PeaShooter'}
要求:自定义元类来控制创建新类
类名必须含有射手(Shooter)
类名首字母大写
如果没有基类默认为object
必须要有注释文档
小坑:不可以直接使用istitle()判断首字母大写,因为这个函数会要求其他字母都是小写
class MyMeta(type):
def __init__(cls, class_name:str, class_bases, class_dict):
if "Shooter" not in class_name:
raise NameError("必须含有Shooter")
elif not class_name[0].istitle():
print(class_name, type(class_name))
raise NameError("必须首字母大写")
elif not cls.__doc__:
raise ValueError("类必须有注释文档")
if not class_bases:
class_bases = (object, )
super().__init__(class_name, class_bases, class_dict)
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
class iceShoot(metaclass=MyMeta):
pass
# NameError: 必须含有Shooter
class iceShooter(metaclass=MyMeta):
pass
# NameError: 必须首字母大写
class IceShooter(metaclass=MyMeta):
pass
# ValueError: 类必须有注释文档
class IceShooter(metaclass=MyMeta):
"""
这是寒冰射手
"""
pass
print(IceShooter.__mro__)
# (, )
class MyMeta(type):
def __call__(self, *args, **kwargs):
print("这是自定义元类的魔法方法call")
print(f"参数self:{self}")
print(f"参数args:{args}")
print(f"参数kwargs:{kwargs}")
return super().__call__(*args, **kwargs)
class A(metaclass=MyMeta):
def __init__(self, *args, **kwargs):
print("这是根据自定义元类创建新类的魔法方法init")
print(f"参数self:{self}")
print(f"参数args:{args}")
print(f"参数kwargs:{kwargs}")
def __call__(self, *args, **kwargs):
print("这是根据自定义元类创建新类的魔法方法call")
print(f"参数self:{self}")
print(f"参数args:{args}")
print(f"参数kwargs:{kwargs}")
a = A("bruce", age=18)
a("tom", age=16)
# 这是自定义元类的魔法方法call
# 参数self:
# 参数args:('bruce',)
# 参数kwargs:{'age': 18}
# 这是根据自定义元类创建新类的魔法方法init
# 参数self:<__main__.A object at 0x00000200C1787DF0>
# 参数args:('bruce',)
# 参数kwargs:{'age': 18}
# 这是根据自定义元类创建新类的魔法方法call
# 参数self:<__main__.A object at 0x00000200C1787DF0>
# 参数args:('tom',)
# 参数kwargs:{'age': 16}
a = A("bruce", age=18)
__call__
___init__
中__call__
来控制自定义类的括号内容a("tom", age=16)
__call__
方法,这是显而易见的,不需要解释class MyMeta(type):
def __call__(cls, *args, **kwargs):
if len(args):
raise TypeError("实例化必须通过关键字传参")
return super().__call__(*args, **kwargs)
class Student(metaclass=MyMeta):
def __init__(self, name, age):
self.name = name
self.age = age
student_one = Student("bruce", 18)
# TypeError: 实例化必须通过关键字传参
student_two = Student(name="tom", age=22)
print(student_two.name, student_two.age)
# tom 22