__new__ ,__init__和__del__

来源:互联网 发布:ssd优化软件 编辑:程序博客网 时间:2024/06/05 15:29

  每个人都知道一个最基本的魔术方法, __init__ 。通过此方法我们可以定义一个对象的初始操作。然而,当我调用 x =SomeClass() 的时候, __init__ 并不是第一个被调用的方法。实际上,还有一个叫做 __new__ 的方法,来构造这个实例。然后给在开始创建时候的初始化函数来传递参数。在对象生命周期的另一端,也有一个 __del__ 方法。我们现在来近距离的看一看这三个方法:

__new__(cls, [...) __new__ 是在一个对象实例化的时候所调用的第一个方法。它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法。 __new__ 方法相当不常用,但是它有自己的特性,特别是当继承一个不可变的类型比如一个tuple或者string。我不希望在 __new__ 上有太多细节,因为并不是很有用处,但是在 Python文档 中有详细的阐述。


__init__(self, […) 此方法为类的初始化方法。当构造函数被调用的时候的任何参数都将会传给它。(比如如果我们调用x = SomeClass(10, 'foo')),那么 __init__ 将会得到两个参数10和foo。 __init__ 在Python的类定义中被广泛用到。


__del__(self) 如果 __new__ 和 __init__ 是对象的构造器的话,那么 __del__ 就是析构器。它不实现语句 del x (以上代码将不会翻译为 x.__del__() )。它定义的是当一个对象进行垃圾回收时候的行为。当一个对象在删除的时需要更多的清洁工作的时候此方法会很有用,比如套接字对象或者是文件对象。注意,如果解释器退出的时候对象还存存在,就不能保证 __del__ 能够被执行,所以 __del__ can’t serve as a replacement for good coding practices ()~~~~~~~

放在一起的话,这里是一个 __init__ 和 __del__ 实际使用的例子。

from os.path import joinclass FileObject:    '''给文件对象进行包装从而确认在删除时文件流关闭'''    def __init__(self, filepath='~', filename='sample.txt'):        #读写模式打开一个文件        self.file = open(join(filepath, filename), 'r+')    def __del__(self):        self.file.close()        del self.file


继承自object的新式类才有__new__

__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供

__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例

__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

例:

>>> class E(object):def __init__(self):print "init"def __new__(cls,*args,**kwargs):print "new %s"%clsreturn super(E, cls).__new__(cls, *args,**kwargs)>>> te = E()new <class '__main__.E'>init>>> >>> print type(te)<class '__main__.E'>
或者

>>> class D(object):def __init__(self):print "init"def __new__(cls,*args,**kwargs):print "new %s"%clsreturn object.__new__(D,*args,**kwargs)>>> td = D()new <class '__main__.D'>init>>> print type(td)<class '__main__.D'>
若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行

>>> class B(object):def __init__(self):print "init">>> class C(object):def __init__(self):print "init"def __new__(cls,*args,**kwargs):print "new %s"%clsreturn object.__new__(B,*args,**kwargs)>>> tc = C()new <class '__main__.C'>>>> print type(tc)<class '__main__.B'>
若没有继承object,也会自动创建对象,但不会执行本身的__new__方法,至于是否调用了object的__new__方法有待探究

>>> class G():def __init__(self):print "init"def __new__(cls,*args,**kwargs):print "new %s"%clsreturn object.__new__(G,*args,**kwargs)>>> tg = G()init>>> print type(tg)<type 'instance'>
>>> isinstance(tg,G)True

__new__ 的作用

依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
首先我们来看一下第一个功能,具体我们可以用int来作为一个例子:
假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。

class PositiveInteger(int):    def __init__(self, value):        super(PositiveInteger, self).__init__(self, abs(value))i = PositiveInteger(-3)print i

但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种 不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。
这是修改后的代码:

class PositiveInteger(int):    def __new__(cls, value):        return super(PositiveInteger, cls).__new__(cls, abs(value))i = PositiveInteger(-3)print i

通过重载__new__方法,我们实现了需要的功能。
另外一个作用,关于自定义metaclass。其实我最早接触__new__的时候,就是因为需要自定义 metaclass,但鉴于篇幅原因,我们下次再来讲python中的metaclass和__new__的关系。



用__new__来实现单例

事实上,当我们理解了__new__方法后,我们还可以利用它来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton) 。
因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。

class Singleton(object):    def __new__(cls):        # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象        if not hasattr(cls, 'instance'):            cls.instance = super(Singleton, cls).__new__(cls)        return cls.instanceobj1 = Singleton()obj2 = Singleton()obj1.attr1 = 'value1'print obj1.attr1, obj2.attr1print obj1 is obj2

输出结果:

value1 value1True


可以看到obj1和obj2是同一个实例。