python通过函数和常规类编写元类

1 python通过函数和常规类编写元类

python可以通过函数和常规类编写元类。函数和常规类之间通过type()创建类对象。

1.1 使用简单的工厂函数

python工厂函数定义了一个外部函数,它生成并返回一个嵌套函数,所以调用工厂函数就可以得到嵌套函数的引用。参考《python嵌套函数作用域》

任何可调用对象都可以作为一个元类,比如函数,只要接收传递的参数,并且返回与目标类兼容的对象。因为可调用对象都有__call__()方法。class语句也是调用type()方法,触发__call()方法。

用法

# 定义元类
def metafunc(classname,supers,classdict):
    pass
    return type(classname,supers,classdict)
# 使用元类
class ClassB(ClassA,metaclass=metafunc)

描述

定义一个工厂函数,接收三个入参,送入到type()内置函数,并且返回type()生成的可调用对象-类对象。

手动调用type()内置函数创建类对象。参考《python元类模型和class语句协议》

classname:字符串,类名;

supers:元组,存放基类;

classdict:类属性字典;

返回:创建名字为classname的类对象,类型为type类。

根据class语句协议,class语句末尾自动调用metaclass,即type()。

示例

>>> def metafunc(classname,supers,classdict):
    print('工厂函数 metafunc.type:',
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
    return type(classname,supers,classdict)

>>> class ClassA:pass

>>> class ClassB(ClassA,metaclass=metafunc):
    name='梯阅线条'
    def meth(self,arg):
        pass

工厂函数 metafunc.type:
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000022F388C88B0>}
>>> cb=ClassB()
>>> cb.name
'梯阅线条'
>>> type(metafunc)
<class 'function'>
>>> type(ClassB)
<class 'type'>
>>> type(cb)
<class '__main__.ClassB'>

1.2 用元类重载类创建调用

用法

# 定义
class SuperMeta(type):
    def __call__(meta,classname,supers,classdict):
        pass
        return type.__call__(meta,classname,supers,classdict)
class SubMeta(type,metaclass=SuperMeta):
    def __new__(meta,classname,supers,classdict):
        pass
        return type.__new__(meta,classname,supers,classdict)
    def __init__(Class,classname,supers,classdict):
        pass
        
# 使用
class ClassB(ClassA,metaclass=SubMeta):pass

描述

通过元类的元类重载type的__call__()方法,再显式调用type的__call__()方法,再触发type子类的__new__()和__init__()方法。

(1) 定义元类SubMeta,继承type,并且指定元类metaclass=SuperMeta;

(2) 定义元类的元类SuperMeta,继承type,重载__call__()方法;

(3) 客户类ClassB通过metaclass=SubMeta指定元类;

(4) 通过class协议触发元类SubMeta,再触发元类的元类SuperMeta的__call__()方法;

(5) SuperMeta的__call__()方法显式调用type.__call__();

(6) type.__call__()调用子类SubMeta的__new__()和__init__()方法;

(7) 子类SubMeta的__new__()方法,显式调用type的__new__()创建类对象,赋值给客户类ClassB;

示例

>>> class SuperMeta(type):
    def __call__(meta,classname,supers,classdict):
        print('调用 SuperMeta.call:',
              'meta: %s' % meta,
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
        return type.__call__(meta,classname,supers,classdict)
>>> class SubMeta(type,metaclass=SuperMeta):
    def __new__(meta,classname,supers,classdict):
        print('调用 SubMeta.new:',
              'meta: %s' % meta,
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
        return type.__new__(meta,classname,supers,classdict)
    def __init__(Class,classname,supers,classdict):
        print('调用 SubMeta.init:',
              'Class: %s' % Class,
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
        print('初始化类对象:',list(Class.__dict__.keys()))

        
>>> class ClassA:pass

>>> class ClassB(ClassA,metaclass=SubMeta):
    name='梯阅线条'
    def meth(self,arg):
        pass

调用 SuperMeta.call:
meta: <class '__main__.SubMeta'>
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000021485ECA3A0>}
调用 SubMeta.new:
meta: <class '__main__.SubMeta'>
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000021485ECA3A0>}
调用 SubMeta.init:
Class: <class '__main__.ClassB'>
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000021485ECA3A0>}
初始化类对象: ['__module__', 'name', 'meth', '__doc__']
>>> cb=ClassB()
>>> cb.name
'梯阅线条'
>>> type(SubMeta)
<class '__main__.SuperMeta'>
>>> type(SuperMeta)
<class 'type'>
>>> type(ClassB)
<class '__main__.SubMeta'>
>>> type(cb)
<class '__main__.ClassB'>

1.3 用常规类重载类创建调用

用法

# 定义
class SuperMeta:
    def __call__(self,classname,supers,classdict):
        Class=self.__New__(classname,supers,classdict)
        self.__Init__(Class,classname,supers,classdict)
        pass
        return Class
class SubMeta(SuperMeta):
    def __New__(self,classname,supers,classdict):
        pass
        return type(classname,supers,classdict)
    def __Init__(self,Class,classname,supers,classdict):
        pass

# 使用        
class ClassA:pass

class ClassB(ClassA,metaclass=SubMeta()):pass

描述

通过常规类模拟元类的元类,重载__call__()方法,调用子类的New方法,New显式调用type()创建类对象赋值给客户类。

(1) 定义常规类SuperMeta模拟元类的元类;

(2) SuperMeta定义__call__()方法,调用子类SubMeta的__New__()和__Init__()方法;

(3) SuperMeta返回客户类Class;

(4) 定义常规类SubMeta,继承SuperMeta,作为客户类的元类;

(5) SubMeta的__New__()方法,显式调用type()方法创建类对象,返回赋值给客户类;

(6) SubMeta的__Init__()方法,对类对象进行初始化;

(7) 定义客户类ClassB,指定元类metaclass=SubMeta()实例对象;

(8) class协议自动调用实例对象SubMeta()的__call__()方法,搜索到SuperMeta的__call__()方法,触发元类SubMeta的New和Init方法;

示例

>>> class SuperMeta:
    def __call__(self,classname,supers,classdict):
        print('调用 SuperMeta.call:',
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
        Class=self.__New__(classname,supers,classdict)
        self.__Init__(Class,classname,supers,classdict)
        return Class

    
>>> class SubMeta(SuperMeta):
    def __New__(self,classname,supers,classdict):
        print('调用 SubMeta.new:',
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
        return type(classname,supers,classdict)
    def __Init__(self,Class,classname,supers,classdict):
        print('调用 SubMeta.init:',
              'Class: %s' % Class,
              'classname: %s' % classname,
              'supers: %s' % supers,
              'classdict: %s' % classdict,sep='\n')
        print('初始化类对象:',list(Class.__dict__.keys()))

        
>>> class ClassA:pass

>>> class ClassB(ClassA,metaclass=SubMeta()):
    name='梯阅线条'
    def meth(self,arg):
        pass

调用 SuperMeta.call:
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000016DC8ADD1F0>}
调用 SubMeta.new:
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000016DC8ADD1F0>}
调用 SubMeta.init:
Class: <class '__main__.ClassB'>
classname: ClassB
supers: <class '__main__.ClassA'>
classdict: {'__module__': '__main__', '__qualname__': 'ClassB', 'name': '梯阅线条', 'meth': <function ClassB.meth at 0x0000016DC8ADD1F0>}
初始化类对象: ['__module__', 'name', 'meth', '__doc__']
>>> cb=ClassB()
>>> cb.name
'梯阅线条'
>>> type(SubMeta)
<class 'type'>
>>> type(SuperMeta)
<class 'type'>
>>> type(ClassB)
<class 'type'>
>>> type(cb)
<class '__main__.ClassB'>

你可能感兴趣的:(python,python)