概述
__new__() 是在新式类中新出现的方法,在 Python 中类实例化时,__new__()方法用在 __init__() 启动之前,决定是否要使用该 __init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。
特性总结:
- __new__()方法是类在准备实例化时调用,也就是实例化之前。
- __new__()方法始终都是类的静态方法,即使没有加上静态方法装饰器。
示例1:
def __new__(cls,*args,**kwargs): ... return object.__new__(cls)
注意:
事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
强化进阶
网上有个很赞的比喻:如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而__new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
示例2:
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 class A(object): 5 static_var = "withClass" 6 7 def __init__(self): 8 self.hostname = "MySql" 9 self.user = "root" 10 11 def mod_user(self,name): 12 self.user = name 13 14 def putongMethed(self): 15 print "普通方法:putongMethod" 16 17 @property 18 def property_var(self): 19 return "property_var" 20 21 @staticmethod 22 def static_method(): 23 print "静态方法:StaticMethod" 24 25 @classmethod 26 def class_method(cls): 27 print "类方法:ClassMethod" 28 29 class B(A): 30 def __new__(cls, *args, **kwargs): 31 print "实例化前的类对象:%s"%cls 32 print "实例化前的类参数:%s"%cls.__dict__ 33 #在这里,B为A的派生类,A为B的基类,调用基类A的__new__()方法,并指向A的__init__()构造函数。 34 return A.__new__(A,*args,**kwargs) 35 36 if __name__=="__main__": 37 obj = B() 38 print "类对象的静态字段:%s"%B.static_var 39 B.static_method() 40 B.class_method() 41 print "类属性:%s" % obj.property_var 42 print "实例对象: %s"%obj 43 obj.putongMethed() 44 print "实例对象的参数:%s"%obj.__dict__ 45 #__new__()仅指定实例构造方法__init__(),并不执行该方法初始化实例 46 obj.__init__() 47 print "执行__init__()初始化的参数:%s"%obj.__dict__ 48 #调用A类中的方法 49 obj.mod_user("mysql") 50 print "调用A类方法修改普通字段: %s"%obj.__dict__
结果:
类对象:<class '__main__.B'> 实例化前的类参数:{'__module__': '__main__', '__new__': <staticmethod object at 0x022E7230>, '__doc__': None} 类对象的静态字段:withClass 静态方法:StaticMethod 类方法:ClassMethod 类属性:property_var 实例对象: <__main__.A object at 0x022E72D0> 普通方法:putongMethod 实例对象的参数:{} 执行__init__()初始化的参数:{'hostname': 'MySql', 'user': 'root'} 调用A类方法修改普通字段: {'hostname': 'MySql', 'user': 'mysql'}
示例解读:
- 经理(__new__())借该工厂(B)的名义向客户(obj)出售完全不是该工厂的产品(A的__init__()以及A类指针)。
- 我们可以看到A类的静态字段,静态方法,类方法都被B类完美继承,可以通过B.xxMethod获得。
- obj=B()实例化时,得到的实例对象的指针却指向了A类,这就是__new__()狸猫换太子,借B工厂将他的父类A给打包出售了。
- 因为obj的类指针指向了A,所以可以调用A的普通方法,这是如果调用B类中的普通方法或静态字段时,就会报错!!
- obj.__dict__()查看实例对象中的参数,发现为空,没错,这里__new__()只是给了个地址(A和A.__init__()的地址),初始化需要手动执行。
- 收到执行obj.__init__()函数后,读取实例对象参数,就得到了A类下的__init__()的数据结构。
类实例化过程
实例对象(独有的命名空间)= 指向类对象的指针 + 普通字段