首页 > 代码库 > Python的__init__, __new__魔法方法以及在__metaclass__元类中的使用

Python的__init__, __new__魔法方法以及在__metaclass__元类中的使用

Python中类的实例化是由Python解释器先后调用__new__,__init__这两个魔法方法来完成的,前者用来完成实例化后的对象的“骨架”(比如,解释器会为对象分配地址,并返回一个指向该对象的引用值,该引用值会被紧接着传递给__init__函数),后者用“ self.属性名 = 属性值 ”这样的方式对实例化的对象进行“填充”。

1.__new__

在一个类(假设为类A)实例化出一个对象的过程中,__new__()方法先于__init__()方法调用,它返回一个A的实例的引用,这个引用值会被传递给接下来执行的方法,如果,__new__()没有返回一个实例的引用,则__init__()不会被执行,若它返回一个非A的实例(语法上可以,但是没有实际意义)b(假设是B的一个实例),它则继续执行b的__init__()方法。

__new__(cls[, ...])__new__()方法的函数形式如左边所示。它是一个静态方法(虽然没有使用静态方法的修饰符),cls的值为类,其他参数为初始化时传递给构造器的参数(就是传递给__init__()的参数),例如,a = A(”Jonhn”,20)这样的语句,解释器在实例化A的时候会自动调用__new__(A,,”Jonhn”,20 ),解释器会把A和收集到的参数传递给__new__(),让它有操作这些数据的能力。所以在定义__new__()的时候,形参的设置最好和__init__()保持一致,尤其是在使用了*args,**kwargs,默认值之后,确保定义的形参能够恰当的接受实参。

class Person():    def __init__(self, name, age):        self.name = name        self.age = age    def __new__(cls, *args, **kwargs):        print("__new__ Method is invoking")        return super(Person, cls).__new__(cls)p = Person("John", 30)print(p.name)print(p.age)

运行结果:

__new__ Method is invokingJohn30

涉及到继承的话,调用祖先类的__new__()方法的一般形式为“

Typical implementations create a new instance of the class by invoking the superclass’s __new__() method using super(currentclass, cls).__new__(cls[, ...]) with appropriate arguments and then modifying the newly-created instance as necessary before returning it.

涉及到继承时,派生类实例化的时候按照MRO搜索__new__(__init__也是一样)并调用,这是设计类体系的时候也应该注意的。

2.__new__的用例

“__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.”

一般的自定义类,是对同一类事物的抽象,而这些所有这些自定义的类,对他们进行抽象,他们的共同特征就是:可以实例化,自定义的类又可以抽象为type的一个实例(好辩证的想法,一会儿是类,一会儿又变成实例),type实例化话后得到一个类,type就被称为元类,我们可以根据需求创建自己的元类,使用在模块里,项目里,使这些类具有某些共同的我们想实现的特征。

这篇文章给出了许多的用例:

浅析python的metaclass

Python的__init__, __new__魔法方法以及在__metaclass__元类中的使用