20230817-105949

Python中类的特殊方法

Builtin Function type

type本身是可以当成一个内置的函数来使用,传入一个参数然后返回这个参数的类型。但是,type本身也可以当作一个类的构造器,此时需要传入3个参数(这里也可以说是根据传入参数个数的不同,type有不同的用法)。传入的三个参数为:

# <type 'int'>
type(3.0)

# <__main__.MyClass object at 0x   >
MyClass = type('MyClass', bases, attrs)

元类

通过上面type方法,我们可以手动的创建一个类,事实上我们常用的class MyClass: 的声明方法,其后台就是采用type来构建类。这里可以引出一个概念---元类,也就是定义如何创建类的类。而在没有特殊指定的情况下,是默认使用metaclass=type来进行类的构建。因此,我们也可以在生成类时使用自定义的元类,以满足各种需求,像单例模式、方法检查等。下面给出一种实现自动注册机制的元类示意(在类构建过程增加对基类方法有无的判断,进而找到那些继承ModelBase的子类,然后在构建类过程中,调用注册方法将其储存在_models字典中):

class AutoRegisterMetaclass(type):

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

	# 类的构建是通过__new__方法,其和__init__、__call__特殊方法的区别在下面进行展开
    def __new__(cls, name, bases, attrs):
        cls = super().__new__(cls, name, bases, attrs)
        for base in bases:
            if hasattr(base, '_NNModel__registerSubclass'):
                base._NNModel__registerSubclass(cls)
        return cls

class ModelBase(metaclass=AutoRegisterMetaclass):
	_models = {}
	def __init__(self):
		pass
	@classmethod
	def __registerSubclass(cls, klass):
		cls._models[klass.__repr__(klass)] = klass

class ModelA(ModelBase):
	def __init__(self):
		pass

辨析特殊方法

至此,我们已经对元类有一个初步的认识,它可以让我们在类生成前,对类的生成进行定制。下图是一个类的处理流程,需要注意的有以下几点:

graph LR;
	subgraph import
		id1[main] ---> id2[class MyClass] ---> id3{custom
metaclass ?}; id3 ---> id4[__new__] ---> id5[class instance]; end subgraph initialize id6["MyClass()"] ---> id7[__init__] ---> id8[instance]; end id5 ---> id6

和装饰器的执行顺序

Python中的装饰器也可以实现在代码执行前进行修饰的功能,但是其和元类还是有明显的功能差距的,个人感觉元类更加面向对象,可以通过继承关系传递给子类;而装饰器可能更灵活些,把一些额外的功能独立出来。把两者放在一起又能碰撞出怎样的火花呢😶‍🌫️?

通过[[#辨析特殊方法]]中对元类中__new__和__init__特殊方法执行的流程进行分析,可以得出元类和类实例的生成要早于装饰器代码的执行(其实也很好理解,因为根据装饰器的语法糖func = decorator(func),肯定要先有fun😂)。

还有一点是在装饰器类本身,同样是根据装饰器语法,可以才想出**类实例生成的返回值(new)**会被传递给被修饰对象,因此有以下几种实现装饰器类的方法:

下面给出目前在项目中,一种装饰器类的实现代码(其实就是通过修改__new__方法实现的):

class Decorator():
    def __init__(self, *args) -> None:
        print("Decorator.init")
        for i in args:
            print(f"arg: {i}")
        
    def __new__(cls, klass):
        print(f"Decorator.__new__ {cls} {klass}")
        klass.__init__ = cls.__init__
        return klass
    
    def __call__(self, *args, **kwds):
        print(f"Decorator.__call__ {args} {kwds}")
        
class MetaclassTest(type):
    def __new__(cls, name, bases, attrs):
        print(f"MetaclassTest.__new__ {cls} {name}")
        print("----end")
        return super().__new__(cls, name, bases, attrs)
    
@Decorator
class A(metaclass=MetaclassTest):
    def __init__(self) -> None:
        print("in A")
        
'''
输出为:
MetaclassTest.__new__ <class '__main__.MetaclassTest'> A
----end
Decorator.__new__ <class '__main__.Decorator'> <class '__main__.A'>
'''