Python中一切皆对象,元类 --> 类 --> 对象。
Python 中的元类(metaclass)是一种用于创建类的“类”。换句话说,元类定义了如何构造类本身
每个类都是一个对象,而元类就是用来创建这些类对象的类
理解元类的概念需要先对 Python 中的类和对象
有一个清晰的认识
基本概念
1. 类和对象:
-
在 Python 中,类(class)用于创建对象(object),类定义了对象的属性和方法
-
对象是类的实例
2. 元类:
-
元类用于创建类本身。换句话说,元类就是
类的类
-
默认情况下,Python 中所有的类都是由
type 元类
创建的
type使用
使用type创建类时,接受三个参数:
-
类名:
'MyClass'
-
基类元组:
(object,)
-
类属性字典:
class_attrs
,案例中为一个初始化方法和一个自定义方法
# 定义类属性和方法
class_attrs = {
'greet': lambda self: f"Hello, my name is {self.name}",
'__init__': lambda self, name: setattr(self, 'name', name)
}
# 动态创建类
MyClass = type('MyClass', (object,), class_attrs)
# 创建类的实例
instance = MyClass('Alice')
# 调用方法
print(instance.greet()) # 输出: Hello, my name is Alice
自定义元类
-
继承
type
元类 -
重载一些方法,如
__new__
和__init__
,来修改类的创建过程
控制类的创建
-
可以在类创建时进行一些自定义操作,比如添加属性或方法,修改现有的属性或方法等
-
例如,可以在元类中自动为类添加某些方法或属性,以简化重复性工作
# 定义一个自定义元类
class MyMeta(type):
def __new__(cls, name, bases, dct):
dct['y'] = 10 # TODO:在类中添加一个属性
return super().__new__(cls, name, bases, dct)
# 使用自定义元类创建类
class MyClass(metaclass=MyMeta):
pass
# 实例化 MyClass
obj = MyClass()
print(obj.y) # 输出:10
动态创建类
# 定义类属性和方法
class_attrs = {
'greet': lambda self: f"Hello, my name is {self.name}",
'__init__': lambda self, name: setattr(self, 'name', name)
}
# 动态创建类
MyClass = type('MyClass', (object,), class_attrs)
# 创建类的实例
instance = MyClass('Alice')
# 调用方法
print(instance.greet()) # 输出: Hello, my name is Alice
实现单例模式
使用元类来控制类的实例化过程,确保一个类只有一个实例
class SingletonMeta(type):
_instances = {}
def __call__(cls, args, *kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=SingletonMeta):
pass
obj1 = SingletonClass()
obj2 = SingletonClass()
print(obj1 is obj2) # 输出:True
可通过继承,实现多个类的元类自定义
# 这里的 MyType 是我们自定义的元类,元类的构建需要继承 type 类,使用__new__方法去定义元类的构造
# 其实原理就是基于继承和重写(继承父类 type 的__new__和__init__进行构造和初始化)
class MyType(type):
def __new__(mcs, *args, **kwargs):
# 创建"类"时调用, 可以在创建"类"时进行扩展
print(f"我是元类构造方法,mcs的id为: {id(mcs)}")
new_cls = super().__new__(mcs, *args, **kwargs) # 这里调用的是父类的构造方法
print(f"新创建的 new_class 的id为: {id(new_cls)}")
return new_cls
def __init__(cls, *args, **kwargs):
# 创建"类"时调用, 可以在创建"类"时进行扩展
print(f"我是初始化方法, cls的id为: {id(cls)}")
super().__init__(*args, **kwargs) # 这里用父类的方法的初始化方法
# Foo类实际一个类但同时也是MyType创建的对象: 创建类时调用元类的__new__方法来创建,__init__方法来初始化
class Foo(object, metaclass=MyType):
pass
"""基于元类实现单例模式"""
class SingletonMeta(type):
"""自定义单例元类:继承type并重写type的构造方法,初始化方法,__call__方法"""
def __init__(cls, *args, **kwargs):
# 本质还是使用父类的初始化方法进行初始化,不过我们可以自定义一些操作,这里我们定义了一个类变量
cls.__instance = None
super().__init__(*args, **kwargs)
def __new__(mcs, *args, **kwargs):
# 本质还是使用父类的构造方法来构造,在构造前我们可以自定义一些操作,这里我们打印一句话
print("先执行我来构造类")
return super().__new__(mcs, *args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
class President(metaclass=SingletonMeta):
"""先执行我们自定义的元类中的__new__和__init__构造和初始化这个类"""
username = None
def get_name(self):
"""Returns the name of the"""
print(self.username)
def set_name(self):
"""Set the name of the administration"""
print(self.username)
# President类是 SingletonMeta 元类实例化出来的一个"对象",由上文可知"对象+()"即可执行 SingletonMeta 中定义的__call__方法
A = President()
B = President()
print(id(A))
print(id(B))
自动注册类
在元类中实现类的自动注册机制,这在需要自动管理多个类时非常有用
registry = {}
class RegisterMeta(type):
def __new__(cls, name, bases, dct):
new_class = super().__new__(cls, name, bases, dct)
registry[name] = new_class
return new_class
class BaseClass(metaclass=RegisterMeta):
pass
class SubClass1(BaseClass):
pass
class SubClass2(BaseClass):
pass
print(registry) # 输出:{'BaseClass': <class '__main__.BaseClass'>, 'SubClass1': <class '__main__.SubClass1'>, 'SubClass2': <class '__main__.SubClass2'>}
验证类定义
在类创建时验证类的属性和方法是否符合某些规则或约定
class ValidatingMeta(type):
def __new__(cls, name, bases, dct):
if 'required_method' not in dct:
raise TypeError("Missing required method 'required_method'")
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=ValidatingMeta):
def required_method(self):
pass # 必须定义这个方法,否则会抛出异常
new、init、call
new & init
-
new是在实例创建之前被调用的,用于创建实例,然后返回实例对象
-
new至少有一个cls参数代表当前类,该参数在实例化时由Python解释器自动识别
-
new必须要有返回值,返回的是实例化出来的实例(如果__new__没有有返回当前实例,__init__方法是不会被调用的)
class A:
def __new__(cls, *args, **kwargs):
print("A.__new__")
return super().__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
print("A.__init__")
self.username = "zheng"
self.password = "zheng"
a = A()
print(a.username, a.password)
# 输出
A.__new__
A.__init__
zheng zheng
基于__new__方法实现单例
class A:
instance = None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self, *args, **kwargs):
print(f"{args[0]}.__init__")
self.password = kwargs.get('password')
a = A("zheng", {"password": "123"})
b = A("xing", {"password": "456"})
print(">>>> ", a is b)
print(a.password)
print(b.password)
# 输出
zheng.__init__
xing.__init__
>>>> True
None
None
call
call方法内部的执行流程是怎样的,为什么实例化一个对象时先执行__new__方法再执行__init__方法?
元类的__call__会先调用type内的__new__方法创造一个空对象
元类的__call__函数会接着调用type内的__init__方法初始化
元类的__call__会返回一个初始化好的对象
class A(object):
def __call__(self, *args, **kwargs):
print("何时调用call方法")
# 类名+(): 实例化出来的一个对象,实际执行的是__new__和__init__方法,此时不调用类中定义的call方法
a = A() # A中没有__new__和__init__就执行父类的__new__和__init__方法
# 对象+(): 此时调用才是A类中定义的__call__方法
a()
元类中使用
"""测试元类"""
class MyType(type):
"""自定义Type类"""
def __new__(mcs, *args, **kwargs):
print(f"元类的构造方法, mcs的id为: {id(mcs)}")
new_cls = super().__new__(mcs, *args, **kwargs)
print(f"新构建类的new_cls的id为: {id(new_cls)}")
return new_cls
def __init__(cls, *args, **kwargs):
print(f"元类的初始化方法, cls的id为: {id(cls)}")
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
print(f"自定义__call__方法,啥都不干使用父类的__call__方法,注意看__call__方法的执行流, cls的id为{id(cls)}")
return super().__call__(*args, **kwargs) # 使用type中的_call__
class Foo(object, metaclass=MyType):
"""重写父类的new init方法"""
def __init__(self, name):
print(f"Foo类的初始化方法, self的id: {id(self)}")
self.name = name
def __new__(cls, *args, **kwargs):
print(f"Foo类的构造方法,cls的id: {id(cls)}")
new_obj = object.__new__(cls)
print(f"新创建的对象new_obj的id为: {id(new_obj)}")
return new_obj
def __call__(self, *args, **kwargs):
print("使用Foo实例化出来的对象的调用")
def get(self):
print("GET {}")
v1 = Foo('SB')
print(v1)
print(v1.name)
v1()
print(f"Foo类的id为: {id(Foo)}")
# 自定义元类
class MyType(type):
# 可以把 类 当作对象来看,type就是类,来创建 类 这个对象的类
def __new__(cls, *args, **kwargs):
print("MyType new")
return super().__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
print("MyType init")
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
# 首先执行父类的 __call__方法,call方法中执行 __new__方法、__init__方法,返回一个实例对象
print("MyType call")
# 调用自身的 __new__方法
new_obj = self.__new__(self)
# 调用自身的 __init__方法
self.__init__(new_obj, *args, **kwargs)
return new_obj
# 使用自定义的type来创建类
# TODO: BB类 其实是 MyType类的 实例对象
class BB(object, metaclass=MyType):
username = "zheng"
def __new__(cls, *args, **kwargs):
print("new BB")
return super().__new__(cls)
def __init__(self, username):
print("init BB")
self.username = username
def __call__(self, *args, **kwargs):
print("BB call")
def create_user(self):
print(self.username)
# 我们说 类是 type类的 实例对象,那么 BB(),就会执行 实例化类的 __call__方法,也就是type类的 __call__方法
B = BB("zheng") # 调用 父类的 __call__方法
print(B.username)
B() # B 是 BB类 的实例化对象,那么 B()调用的就是 实例化类-BB的 __call__方法
上述代码执行流程:
-
MyType
的__new__
和__init__
方法在创建BB
类时被调用。 -
MyType
的__call__
方法在实例化BB
类时被调用。 -
在
MyType.__call__
方法中,BB
类的__new__
方法和__init__
方法依次被调用来创建实例。 -
打印实例的
username
属性。 -
调用实例的
__call__
方法。
评论区