python __new__ __init__
写过python类的都会知道__init__,可能也了解__new__。我之前也了解__new__,但只做的它发生在__init__之前。其他的就比较模糊了
今天在学习单例模式时,看到有人用__new__去实例化,也有人用__init__去初始化,甚为奇怪,就查了一下别人的文章,总结一下。
简单来说,就是__new__负责返回一个实例,__init__负责初始化返回的那个实例,就是给返回的实例加上一些属性。__init__方法必须覆写,而__new__方法一般在__init__之前自动执行。如果__new__不能正确返回对象,__init__就不会调用,除非我们自己覆写了__new__,没有正确返回实例,否则不会出现这种情况。
例子来一发
class Human(object): def __init__(self,n,a): print "__init__ called" self.name = n self.age = a def __new__(cls, name,age): print "__new__ called" return super(Human,cls).__new__(cls,name,age) def tell(self): print "My nama is %s,my age is %d"%(self.name,self.age) h = Human("lll",11) 输出: _new__ called __init__ called
这个就是我们经常用到的__init__,从输出结果显而易见,__new__先调用,__init__后调用。当我们去实例化一个对象时,基本过程是:
1.h = Human("lll",11)
2.有了第一步后,python解释器会立马去调用__new__,这个方法会返回一个Human的实例,并且给这个实例绑定了属性,这里就是name和age两个属性。方法的调用一般就是super(Human,cls).__new__(cls,name,age)这种格式。
3.__init__会接收到__new__返回的实例对象,和已经绑定的属性,然后给这些属性赋值,就是self.name = n ,self.age = a,给name属性赋值传递进来的n,age属性赋值传递进来的a。到此一个对象就建立完毕,可以用这个对象去调用其他方法了
所以__init__主要是用于初始化对象,给属性赋值,或者做一些比如print的事情,属于实例级别的方法__init__没有返回,__new__是生产一个实例,属于类级别的方法。__new__有返回值,返回新的对象。
刚才的__new__我们平时是不会去写出来的,属于自动调用。但是,有时候我们并不想让它去自动调用,就必须覆写它。
比如,如果我们的类继承自int,str,tuple这些类时,这些类是不可变的,所以在产生实例时他就是不可变的,但是我们继承了不可变的类又想让它可变,就只能去覆写它的__new__
比如我想判断一个数字是不是正数,就要继承int(可以保证是一个数字),然后在初始化中去判断,不是专门写一个函数去判断。
class ifPositive(int): def __init__(self,value): super(ifPositive,self).__init__(self,True if value>0 else False) i = ifPositive(3) 返回的是3,不是我们期待的1(此处不是返回True,是1,如果不是正数则返回0)
下面通过覆写__new__方法实现功能
class ifPositive(int): def __new__(cls,value): 这里的第一个参数默认是cls return super(ifPositive,cls).__new__(cls,True if value>0 else False) 此处一定要加return i = ifPositive(2) 返回1 i = ifPositive(-1) 返回0
查这两个方法时也看到__call__,此处也补充一下
一个类实现了这个函数,那么它的实例就多了一个功能,可以当作函数来用,直接在对象后面加上括号,里面就是__call__的参数,就会返回__call__方法的结果。还就拿上面的Human类,比如我给那个Human类加了一个方法
def __call__(self,attr): if attr == "name": return self.name else: return self.age h = Human("lll",11) print h("name") 会返回“lll"