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"

 

posted on 2015-11-21 23:04  slower  阅读(502)  评论(0编辑  收藏  举报