【Python】元类及元类如何定义

元类的定义及初始化类的流程

默认由type创建。
怎么让一个类的创建改成其他的东西?用元类。

默认创建类

# 默认创建类,一般写法
class Foo(object):
  pass

# type 创建类
type('Foo', (object, ), {'v1': 123, 'func': lambda self: 666})

自定义元类

class Mytype(type):
  def __new__(cls, *args, **kwargs):
      # 创建类
      fooCls = super().__new__(cls, *args, **kwargs)
      return fooCls

  def __init__(self, *args, **kwargs):
      super().__init__(self, *args, **kwargs)

  def __call__(self, *args, **kwargs):
      # 1. 调用自己那个类的__new__方法去创建对象
      emptyObject = self.__new__(self)
      # 2. 调用自己那个类的__init__方法去初始化
      self.__init__(emptyObject, *args, **kwargs)
      return emptyObject

class Foo(object, metaclass=MyType):
  def __init__(self, name, *args, **kwargs):
    self.name = name

v1 = Foo('alex')   

# 自定义type 创建类
class Foo(Object, metaclass=MyType):
  pass

# Foo是个对象,由MyType创建,所以会执行MyType里的__new__和__init__方法。

类加()执行的是__new__和__init__方法
对象加()执行的是__call__方法

class Foo(object):
  def __call__(self, *args, **kwargs):
    return 1

obj = Foo()
obj()

在__call__方法里面会初始化Foo对象。

  • 比如Foo的__init__中有一些赋值或者逻辑,此时在元类的中的__call__会调用类的__init__方法,将Foo.__init__接收到的参数传入到type的__init__方法中,在type.__init__中完成赋值或逻辑操作。

不管是自定义的元类还是使用默认的类的实例方法(默认就是用type),类的初始化都是在元类的__call__方法中实现的。

  • 创建类的时候是调用了元类的__new__和__init__方法,此时这里不执行__call__方法。
  • 实例化这个类的时候才调用了元类的__call__方法,这时候才会调用元类中的__call__方法,在这个元类中的__call__方法里会初始化类对象(调用类对象的__new__和__init__方法)
  • 如果想调用自己类中的__call__方法,就在自己实例化类的对象后面加括号。

所有创建的类都是元类的对象

# 关系图

# 元类
class Mytype(): pass

# 自己创建的类,这里会调用元类的__new__和__init__方法。
class Foo(): pass

# 自己创建的类的实例化(对象),这里会调用元类的__call__方法。
v1 = Foo()

# 调用自己类的__call__方法。
v1()

元类深入

  • 类中metaclass,自己类由metaclass定义的类来创建。
  • 类继承某个类,父类有自定义metaclass,自己类由metaclass定义的类来创建。
class FormMeta(type): pass

def withMetaclass(meta, base=object):
    # Foo = type('Foo', (object, ), {'v1': 123, 'func': lambda self: 666})
    # 返回一个类(基于meta创建了一个类),这个对象的元类是meta参数,并且继承base参数,类名是NewBase
    return meta('NewBase', (base, ), {})

class NewBase(BaseForm, metaclass=FormMeta): pass

class Form(withMetaclass(FormMeta, BaseFrom)): pass
# 等价于
class Form(NewBase): pass

元类总结

元类的作用

  • 在类创建,实例化对象前后,可以自定义一些功能。
posted @ 2021-11-03 11:10  阿初  阅读(127)  评论(0编辑  收藏  举报