zoukankan      html  css  js  c++  java
  • 元类( 控制对象产生和控制类产生)模板

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

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

    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方法是 控制类的初始化

  • 相关阅读:
    Mac OS X系统下的Android环境变量配置
    mac 终端 常用命令
    如何在mac本上安装android sdk
    让浏览器支持Webp
    ngCordova安装配置使用教程
    js中const,var,let区别
    avaScript技术面试时要小心的三个问题
    视频H5のVideo标签在微信里的坑和技巧
    Git 忽略一些文件不加入版本控制
    "The /usr/local directory is not writable."解决方法
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/11461952.html
Copyright © 2011-2022 走看看