1. __new__和__init__的简介
在Python中,__new__和__init__都是用来创建一个对象的方法。可以说,在Python的类实例化时,它们是不可或缺的。
__new__:这个方法是用来创建对象的,在实例化之前被调用。这个方法必须返回一个对象,如果不返回,那么__init__就不会被调用。
__init__:这个方法是在对象实例化之后被调用。它的主要作用就是初始化对象的属性和方法。
在Python中,所有的类都有一个共同的父类叫做object。这个父类中也有一个__new__方法,这个方法是用来分配对象空间的,一般情况下不需要自己去定义__new__方法,除非你需要精细控制对象的创建过程。
2. __new__和__init__的区别
__new__和__init__这两个方法的作用不一样,因此它们的区别也比较明显。
2.1 __new__和__init__的执行顺序
__new__在__init__之前执行,在创建对象时进行调用,__new__返回一个实例化后的对象,然后传给__init__方法。
class A:
def __init__(self):
print('init执行')
def __new__(cls, *args, **kwargs):
print('new执行')
return super(A, cls).__new__(cls)
a = A()
输出:
new执行
init执行
分析:在实例化时,__new__先被调用,返回一个实例化后的对象传给__init__方法,__init__再对这个对象进行初始化,在这里打印了'new执行'和'init执行'。
2.2 __init__方法的参数
__init__方法的第一个参数是self,它表示实例化后的对象本身。实例化时,__init__方法不需要显示传递self参数,因为Python解释器会自动将对象传给self参数。
2.3 __new__方法的参数
__new__方法的第一个参数是cls,代表当前类对象。__new__方法还可以接收其他的参数,这些参数会传递给__init__方法用于初始化实例化后的对象的属性和方法。
2.4 __new__方法的返回值
__new__方法必须返回一个实例化后的对象,如果不返回,那么__init__方法就不会被调用。__new__方法的返回值可以是其他类的实例化对象,但是在这种情况下__init__方法不会被调用,因为这个对象已经被创建过了。
2.5 __init__方法的返回值
__init__方法不需要返回值,如果它返回了None,那么Python解释器会自动将self对象返回。如果它返回了其他类型的值,则会抛出TypeError异常。
3. __new__和__init__的应用场景
3.1 在子类中处理父类和自身的属性
在子类中,我们可以通过覆盖__new__方法来处理父类和自身的属性。如果我们需要自定义父类中的属性,可以在子类的__new__方法中进行处理,然后再传递给__init__方法。
class A:
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
A.__init__(self, a)
self.b = b
def __new__(cls, a, b):
if a > b:
return super(B, cls).__new__(cls)
else:
return 'error'
b = B(10, 5)
分析:这个例子中,我们要求a必须大于b才可以创建对象。如果a>b,那么调用父类A的__init__方法对属性进行初始化,否则返回'error'。
3.2 单例模式的实现
单例模式是一种常用的设计模式,在系统中只需要一个实例对象的时候使用。在Python中,我们可以通过实现__new__方法来实现单例模式。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b)
分析:这个例子中,我们通过判断Singleton是否存在_instance属性来判断是否已经创建了实例,如果没有就调用基类的__new__方法创建实例,如果已经存在则返回已有的实例,这样就保证了系统中只有一个实例对象。
3.3 metaclass的使用
在Python中,我们可以编写metaclass来动态修改类的定义,这样就可以实现各种高级功能,比如ORM、自动注入依赖等。
class Meta(type):
def __init__(cls, name, bases, dct):
super(Meta, cls).__init__(name, bases, dct)
cls.a = 10
class A(metaclass=Meta):
pass
print(A.a)
分析:这个例子中,我们定义了一个Meta类,并实现了它的__init__方法,这个方法在类定义时被调用。在这个方法中,我们可以动态地修改类的定义,这里定义了a属性,并赋值为10。然后我们定义了一个A类,并指定它的metaclass为Meta,这样就可以通过A访问到Meta定义的属性a。
4. 总结
在Python中,__new__和__init__方法都是用来创建一个对象的方法,但是它们的作用和用法都不同。__new__方法在实例化之前被调用,在其中可以对类进行一些操作,比如修改实例化后对象的属性值。__init__方法在对象实例化之后被调用,在其中可以对实例化后的对象进行初始化操作,比如给对象添加属性和方法。
此外,在Python中我们还可以通过覆盖__new__方法来实现单例模式,在metaclass中动态定义类,这样就可以实现各种高级应用场景,比如ORM等。