元类( 控制对象产生和控制类产生)模板

首先,我们已经知道元类就是产生类的类
那么我就可以通过自定义元类的方式,去实现 控制对象的产生,以及 去控制类对象的产生

一、自定义元类控制对象的产生过程

  1. 首先,先定义个一个自定义元类。自定义元类的特征: (必须继承type)

    class Mymeta(type):
        ...
    
  2. 再定义类时加上metaclass=自定义的元类名。如:class Person(metaclass=Mymeta)

    注意:其实这里通过class Person(metaclass=Mymeta)已经通过type创建了类,然后你才能使用这个类对象。不懂没关系,后面再说

  3. 接着,我们知道当对象加()是去调用类中call()方法。
    那么,**当类加()去实例化一个对象时,类对象会去调用 它类中的这个call方法。因为我们已经指定了自定义元类,因此类对象会去自定义元类中去调用 call方法 **

    class Mymeta(type):
        def __call__(self,*args,**kwargs): # 类对象调用它的绑定方法,不需要传递self
            ...
    p = Person(name='xc')  # 第一步:Person这个 类对象回去调用自定义元类中的call方法,并传递参数
    
  4. 接着,已经进入了类对象的绑定方法call,参数也传了过来。(*args和**kwargs分别是位置参数和关键字参数,他们都是可选参数,可写可不写的)。此时call方法的self,是Person这个类对象,因为call方法是Person的绑定方法

  5. 然后在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方法创建对象
    
  6. 此时,我们通过new方法已经得到了obj这个全新的对象,这个obj是Person类的实例化对象,只不过obj对象中什么内容都还没有

  7. 然后,我们通过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绑定方法,完成实例化对象
    

二、自定义元类控制类的产生过程

之前我们已经知道,通过类来实例化对象的全部过程。
那么现在,我们也可以通过自定义元类来模拟和控制 实例化类的产生。实际上,元类产生类和自定义元类产生对象是一样的

  1. 之前我们说了,当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方法
        ...
    
  2. 调用自定义元类中的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方法是 控制类的初始化

posted @ 2019-09-04 22:30  正在学习的Barry  阅读(347)  评论(0编辑  收藏  举报
-->