python __init__与 __new__的区别

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等。

后端开发标签