首先,我们已经知道元类就是产生类的类。
那么我就可以通过自定义元类的方式,去实现 控制对象的产生,以及 去控制类对象的产生
一、自定义元类控制对象的产生过程
-
首先,先定义个一个自定义元类。自定义元类的特征: (必须继承type)
class Mymeta(type): ...
-
再定义类时加上metaclass=自定义的元类名。如:
class Person(metaclass=Mymeta)
注意:其实这里通过
class Person(metaclass=Mymeta)
已经通过type创建了类,然后你才能使用这个类对象。不懂没关系,后面再说 -
接着,我们知道当对象加()是去调用类中call()方法。
那么,**当类加()去实例化一个对象时,类对象会去调用 它类中的这个call方法。因为我们已经指定了自定义元类,因此类对象会去自定义元类中去调用 call方法 **class Mymeta(type): def __call__(self,*args,**kwargs): # 类对象调用它的绑定方法,不需要传递self ... p = Person(name='xc') # 第一步:Person这个 类对象回去调用自定义元类中的call方法,并传递参数
-
接着,已经进入了类对象的绑定方法call,参数也传了过来。(*args和**kwargs分别是位置参数和关键字参数,他们都是可选参数,可写可不写的)。此时call方法的self,是Person这个类对象,因为call方法是Person的绑定方法
-
然后在call方法中,我们应该通过new方法去创建一个新的对象。这里的 new方法是object类中的静态方法(谁都可以用的),因此我们可以通过指名道姓的去调用。也可以通过self去调用(必须没有在Person类中重写new方法),因为self去调用的是object的new方法。(Python3中的所有类都是继承于object的)
# 这两个方法都可以实现相同的目的 # obj=self.__new__(self) # 方法1,通过self的new方法创建对象 obj=object.__new__(self) # 方法2,通过object的new方法创建对象
-
此时,我们通过new方法已经得到了obj这个全新的对象,这个obj是Person类的实例化对象,只不过obj对象中什么内容都还没有。
-
然后,我们通过obj去调用它的init绑定方法去进行初始化对象(obj就是Person类的实例化对象),完成初始化后返回该对象。此时,我们已经完成了类实例化核对象。
class Mymeta(type): def __call__(self, *args, **kwargs): obj=object.__new__(self) # 通过object的new方法创建对象 obj.__init__(*args, **kwargs) # 调用对象的init方法,完成对象的初始化 return obj class Person(metaclass=Mymeta): def __init__(self, name): # 被自定义元类中的call方法来调用对象的init方法 print(1) self.name = name p = Person(name='xc') # 通过类对象的call绑定方法,完成实例化对象
二、自定义元类控制类的产生过程
之前我们已经知道,通过类来实例化对象的全部过程。
那么现在,我们也可以通过自定义元类来模拟和控制 实例化类的产生。实际上,元类产生类和自定义元类产生对象是一样的
-
之前我们说了,当
class Person(metaclass=Mymeta)
时,就已经通过type创建了类(这时类的属性,已经存在了name,bases,dic)。在之前我们也说过,class
关键字就是在内部调用了type产生了类对象。那么在type内部也是同样通过call方法去创建类对象,只不过type的call方法,我们是看不到的,他是在解释器源码中。但是我们知道在type的call方法中实际上也是调用了new方法去产生了类对象。在只不过他不再是通过object的new方法去创建对象,而是通过type的new方法去创建了类。因此我们可以在自定义元类中重写new方法。这样当type的call方法调用new方法时,就是去自定义元类的new方法(因为自定义元类是继承type的)class Mymeta(type): def __new__(cls, *args, **kwargs): return type.__new__(cls,*args,**kwargs) # type的new方法也是静态方法,因此需要传入类对象 # Person=Mymeta(name,bases,dic) 调用type的__call__,内部调用了Mymeta.__new__,又掉Mymeta的__init__ class Person(metaclass=Mymeta): # 实际上是先调用元类的call方法,再回调自定义元类的new方法和init方法 ...
-
调用自定义元类中的new方法也必须去调用type类中的new方法才能创建类对象。(不同的是,object的new方法是创建一个对象,这个对象什么都没有。但是type的new方法创建类,是默认就会把类属性 name,bases,dic 放到类的名称空间中)接着在type类中的call方法还会去调用自定义元类的init方法,因此我们也可以通过重写init方法去控制类对象的初始化,添加一些类属性。这时类已经创建完毕,可以通过类名来查看类的名称空间和打印结果
class Mymeta(type): def __call__(self, *args, **kwargs): print(2) print(self.mro()) # 类对象的属性查找顺序 obj=object.__new__(self) # 方法2,通过object的new方法创建对象 obj.__init__(*args, **kwargs) # 调用对象的init方法,完成对象的初始化 return obj def __new__(cls, *args, **kwargs): return type.__new__(cls,*args,**kwargs) # type的new方法也是静态方法,因此需要传入类对象 def __init__(self,*args): print(3) self.age = '18' # 把age作为类属性放入类名称空间中 # Person=Mymeta(name,bases,dic) 调用type的__call__,内部调用了Mymeta.__new__,又掉Mymeta的__init__ class Person(metaclass=Mymeta): # 实际上是先调用元类的call方法,再回调自定义元类的new方法和init方法 # age = '18' # 已经在自定义元类的init方法中,把age作为类属性放入类名称空间中 def __init__(self, name): # 被自定义元类中的call方法来调用对象的init方法 print(1) self.name = name p = Person(name='xc') # 先调用自定义元类的call方法 print(Person.__dict__) print(p.__dict__) print(p)
3
2
[<class 'main.Person'>, <class 'object'>]
1
{'module': 'main', 'init': <function Person.init at 0x00000280917C1B70>, 'dict': <attribute 'dict' of 'Person' objects>, 'weakref': <attribute 'weakref' of 'Person' objects>, 'doc': None, 'age': '18'}
{'name': 'xc'}
<main.Person object at 0x00000280916A1D30>
三、模板:控制对象的产生
### 模板:控制对象的产生
class Mymeta(type):
def __call__(self, *args, **kwargs):
# 这里可以填充控制对象产生的代码
obj=object.__new__(self)
obj.__init__(*args, **kwargs)
return obj
class Myclass(metaclass=Mymeta):
def __init__(self,name):
self.name=name
p=Myclass('xc')
四、模板:控制类的产生
### 模板:控制类的产生
class Mymeta(type):
def __init__(self,*args): # 类的初始化绑定方法
pass # 可以做的初始化操作
def __new__(cls, *args, **kwargs): # 类的生成类的方法
# 这里填充一些生成类之前的操作
return type.__new__(cls,*args,**kwargs)
class Myclass(metaclass=Mymeta): # 这里就会产生类,调用自定义元类的new和init
def __init__(self,name):
self.name=name
总结
自定义元类中的call方法是 控制对象的产生
自定义元类中的new方法是 控制类的产生
自定义元类中的init方法是 控制类的初始化