元类的一些应用,实现假的元类,扩展元类

本文详细介绍了Python中元类的基本概念及其应用场景,包括如何自定义元类、元类与装饰器的区别及结合使用、元类在类扩展和管理中的作用等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

元类基础

啰嗦一下:

必须再次申明类(class) 是被创建出来的,由type类的__call__创建 : class x = type('x',x.__bases__,{classdict}) .

如果类涉及了继承以及元类 那么 class Person(继承类 ,... metaclass = 元类);

 

下面有一个例子是元类也能做到像装饰器一样,

但需要说明的是,装饰器在执行代码的时候, 类已经创建完成了,而元类则是创建类的过程

下面代码中的元类都重载了__new__ ,而没有重载元类的__init__ 

原因是元类的__new__ 调用完后class已经创建完毕,  

而元类的__init__ 跟使用类装饰器来修改class没什么区别了 : 元类与装饰器的混合应用

 

 

#任何一个可调用的对象就可以作为元类,不必非得是一个继承type的类.
#可以用一个函数假装成元类
def meta_func(classname, bases , classDict):
    print('call meta_func:',classname,bases,classDict , sep='\n')
    return type(classname,bases,classDict)     #还是由type函数来创建类对象

class  Person(metaclass=meta_func):
    person_data = 123
    def __init__(self):
        print('__init__')

有个细节需要注意(即方法的查找,这里可能太细微了,平常根本不需要注意) .另元类本身并不创建实例 :

#2个元类, 重复一下,元类本身不创建实例
class  super_meta(type):        #顶层元类 ,重定义__call__
    def __call__(self, *args, **kwargs):
        print('Super_meta __call__ :',self,args,kwargs,sep='\n')
        aClass = type.__call__(self,*args,**kwargs)        #返回已经创建的类对象(并不是元类对象!!!)
        print('->>>>>Super_meta class 创建完成:',aClass)
        return aClass
#还是一个元类, 元类本身还可以有元类,可元类并不会被实例化!!!
class  sub_meta(type,metaclass=super_meta):
    def __new__(cls, *args, **kwargs):                    #重定义__new__
        print('sub_meta __new__:',cls, args,kwargs,sep='\n')
        return type.__new__(cls,*args,**kwargs)         #调用父类的__new__
    def __init__(self,*args,**kwargs):                    #重定义__init__
        print('sub_meta __init__:',self,args,kwargs,sep='\n')
#这2个类没有任何输出,反证了元类本身并不会被实例化,这里需要注意的是__call__的调用, 元类的查找过程与一般类的继承查找方式不一样.因为元类不会被实例化
#class Person(metaclass=sub_meta):
#    person_data = 123
#    def method(self):
#       print('Person.method')
#这部分被注释的代码,其执行流程是
#Person 会被sub_meta 创建, 调用Super_meta的__call__
#Super_meta的__call__ 将调用sub_meta的__new__ , __init__

 

前面说了,不是非得是type的子类才能作为元类,只要是可调用的对象都可以,自己实现一个假的元类:

 

#一个可调用的对象(__call__),就可以实现一个元类
#自定义2个函数 New , Init 模拟 __new__ , __init__ 过程
class Meta:
        def __New__(self,*args,**kwargs):
            print('Meta __New__:',self,args,kwargs,sep='\n')
            return type(*args,**kwargs)
        def __Init__(self,*args,**kwargs):
            print('Meta __init__:',self,args,kwargs,sep='\n')
        def __call__(self, *args, **kwargs):
            print('Meta __call__:',self,args,kwargs,sep='\n')
            aClass = self.__New__(*args,**kwargs)
            print('Class生成了:',aClass)
            self.__Init__(aClass,*args,**kwargs)
            return aClass

class Person(metaclass=Meta()): #注意这里是Meta() ,是一个实例, 否则__call__ 无法被调用,而如果是type子类则不需要
    person_data = 123
    def __init__(self):
        print('Person __init__')

 

元类与继承:

元类是创建类的一个类 . 当父类有元类声明时, 子类也会由该元类创建

class Meta1(type):
    def __new__(cls, *args, **kwargs):
        print('meta1 __new__ : ' , args)
        return type.__new__(cls,*args,**kwargs)
    def toast(cls):
        print('toast')
#父类指定了元类
class Super(metaclass=Meta1):
    def sp(self):
        print('super')
#子类继承父类, 那么子类也会由父类指定的元类创建
class sub(Super):
    def sb(self):
        print('sub')
#echo:
#meta1 __new__ :  ('Super', (), {'__module__': '__main__', '__qualname__': 'Super', 'sp': <function Super.sp at 0x0200EAE0>})
#meta1 __new__ :  ('sub', (<class '__main__.Super'>,), {'__module__': '__main__', '__qualname__': 'sub', 'sb': <function sub.sb at 0x0200EA98>})

 

#注意
s = sub()
#s.toast()      将出错.实例的属性查找只会搜索自身以及实例.__class__及其父类们的__dict__ ,元类不包含在其中!!

再声明一下,元类只是创建类的一个玩意

 

 

接下来,看看基于元类的一些扩展类的方式:

 

 

#基于元类扩展类.
#把一下2个函数添加进类中, 方式有很多
# 可以直接添加 :className.xx = some_func
# 可以用装饰器 :def decorator(aClass):aClass.xx = some_func ; return aClass
# 这里使用元类来实现
def first_func(obj):
    print( obj.value  * 2)
def sec_func(obj):
    print(obj.value * 3)

class ExtendMetaClass(type):                        #元类定义,继承type
    def __new__(meta, classname,bases, classdict):
        classdict['first_func'] = first_func       #在命名空间词典中添加2个属性,指向2个函数
        classdict['sec_func'] = sec_func
        print('__new__ :',meta, classname,bases, classdict)
        return type.__new__(meta,classname,bases,classdict)

class client1(metaclass=ExtendMetaClass):       #使用元类来创建client1 类对象
    def __init__(self,value = 2):
        self.value = value
    def x(self):
        return self.value ** 2

class client2(metaclass=ExtendMetaClass):      #使用元类来创建client2类对象
    value = 123

c = client1()
c.first_func()
c.sec_func()
#echo:
#__new__ : <class '__main__.ExtendMetaClass'> client1 () {'__module__': '__main__', '__qualname__': 'client1', '__init__': <function client1.__init__ at 0x01FEDBB8>, 'x': <function client1.x at 0x01FEDB70>, 'first_func': <function first_func at 0x01FEDED0>, 'sec_func': <function sec_func at 0x01FEDC90>}
#__new__ : <class '__main__.ExtendMetaClass'> client2 () {'__module__': '__main__', '__qualname__': 'client2', 'value': 123, 'first_func': <function first_func at 0x01FEDED0>, 'sec_func': <function sec_func at 0x01FEDC90>}
#4
#6

 

*元类基本上是用来管理类本身的(在创建/初始化类对象的时候做一些事) .

 

但是也可以像装饰器一样使用元类(这并不是一种好的用法,先声明下,这种做法比较隐晦):

#把元类假装成装饰器来使用;
#注意:这个例子实际不太好,只是用来扩展元类的用法.这种用法比较隐晦
def tracer(*args):
    print('创建Person类对象')
    aClass = type(*args)   #利用type来创建Person类对象
    print('创建Person完成:',aClass)
    class Wrapper:         #内部类 ,默认使用type 创建Wrapper 类对象
        def __init__(self,*args,**kwargs):
            self.wrapper = aClass(*args,**kwargs)       #实例对象添加一个属性,把Person实例嵌入
        def __getattr__(self, attr):
            print('tracer:',attr)
            return getattr(self.wrapper,attr)
    return Wrapper                          #返回由type创建的Wrapper

class Person(metaclass=tracer):             #此时这个Person 已经是Wrapper了,Wrapper由type创建s
    def __init__(self,name='Person',age=10):
        self.name = name
        self.age = age
    def display(self):
        print(self.name,self.age)
print('现在的Person是什么:',Person) #<class '__main__.tracer.<locals>.Wrapper'>
p = Person()
p.display()
#echo:
#创建Person类对象
#创建Person完成: <class '__main__.Person'>
#现在的Person是什么: <class '__main__.tracer.<locals>.Wrapper'>
#tracer: display
#Person 10

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值