首先回顾之前类的所有篇章:
从基本认识类,到深入认知类的属性、方法、访问控制、继承、限制等,最终完成一篇类的完整构造,如何去构建一个类。
1、类构造和初始化
我们定义一个类,并生成初始化_ _ init _ _ 对象函数和 _ _ new _ _对象函数:
class A(object):
def __init__(self,*args, **kwargs):
print "init %s" %self.__class__
def __new__(cls,*args, **kwargs):
print "new %s" %cls
return object.__new__(cls, *args, **kwargs)
a = A()
输出结果:
new <class '__main__.A'>
init <class '__main__.A'>
从结果可以看出,当实例化A类时,”_ _new _ _ “方法首先被调用,然后是” _ _ init _ _”方法。
一般来说,”_ _ init _ _ “和” _ _ new_ _”函数都会有下面的形式:
def __init__(self, *args, **kwargs):
# func_suite
def __new__(cls, *args, **kwargs):
# func_suite
return obj
对于”_ _new _ _ “和” _ _ init _ _”可以概括为:
前面文章中已经介绍过了”_ _ init _ _ “的一些行为,包括继承情况中” _ _ init _ _ “的表现。下面就重点看看”_ _ new _ _”方法。
2、_ _ new_ _特性
“_ _ new_ _”是在新式类中新出现的方法,它有以下行为特性:
对于上面的第三点,如果当前类是直接继承自 object,那当前类的 “_new_” 方法返回的对象应该为:
def __new__(cls, *args, **kwargs):
# func_suite
return object.__new__(cls, *args, **kwargs)
2.1、重写_ _ new_ _
如果(新式)类中没有重写”_ _ new _ _ “方法,Python默认是调用该类的直接父类的” _ _ new_ _ “方法来构造该类的实例,如果该类的父类也没有重写” _ _ new _ _ “,那么将一直按照同样的规则追溯至object的” _ _new_ _”方法,因为object是所有新式类的基类。
而如果新式类中重写了”_ _new_ _ “方法,那么可以选择任意一个其他的新式类(必须是新式类,只有新式类有”_ _ new_ _ “,因为所有新式类都是从object派生)的”__ _ new _ _”方法来创建实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。
class Fun(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
# 这里的object.__new__(cls, *args, **kwargs) 等价于super(Fun, cls).__new__(cls, *args, **kwargs)
# object.__new__(Fun, *args, **kwargs)
# Ny.__new__(cls, *args, **kwargs)
# person.__new__(cls, *args, **kwargs),即使person跟Fun没有关系,也是允许的,因为person是从object派生的新式类
# 在任何新式类,不能调用自身的“__new__”来创建实例,因为这会造成死循环
# 所以要避免return Fun.__new__(cls, *args, **kwargs)或return cls.__new__(cls, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
class Ny(Fun):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
class person(object):
# person没有“__new__”方法,那么会自动调用其父类的“__new__”方法来创建实例,即会自动调用 object.__new__(cls)
pass
class girl(object):
def __new__(cls, *args, **kwargs):
# 可以选择用Bar来创建实例
obj = object.__new__(Ny, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
fun = Fun()
ny = Ny()
girl = girl()
输出结果:
Call __new__ for <class '__main__.Fun'>
Call __new__ for <class '__main__.Ny'>
Call __new__ for <class '__main__.Ny'>
2.2 、_ _ init_ _的调用
“_ _ new _ _ “决定是否要使用该类的” _ _ init_ _ “方法,因为”_ _ new _ _” 可以调用其他类的构造方法或者直接返回别的类创建的对象来作为本类的实例。
通常来说,新式类开始实例化时,”_ _ new _ _ “方法会返回cls(cls指代当前类)的实例,然后调用该类的”_ _ init_ _ “方法作为初始化方法,该方法接收这个实例(即self)作为自己的第一个参数,然后依次传入” _ _new _ _”方法中接收的位置参数和命名参数。
但是,如果”_ _ new _ _ “没有返回cls(即当前类)的实例,那么当前类的” _ _ init_ _”方法是不会被调用的。看下面的例子:
class A(object):
def __init__(self, *args, **kwargs):
print("Call __init__ from %s" %self.__class__)
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
class B(object):
def __init__(self, *args, **kwargs):
print("Call __init__ from %s" %self.__class__)
def __new__(cls, *args, **kwargs):
obj = object.__new__(A, *args, **kwargs)
print("Call __new__ for %s" %obj.__class__)
return obj
b = B()
print(type(b))
输出结果:
Call __new__ for <class '__main__.A'>
<class '__main__.A'>
2.3、派生不可变类型
例如,Python中float是不可变类型,如果想要从float中派生一个子类,就要实现”_ _ new _ _”方法:
class RoundTFloat(float):
def __new__(cls, num):
num = round(num, 4)
#return super(Round2Float, cls).__new__(cls, num)
return float.__new__(RoundTFloat, num)
num = RoundTFloat(3.141592654)
print(num) #3.1416
3、定制一个类
文中介绍了类的构造和初始化方法:”_ _ new _ _”和” _ _ init _ _ “。” _ _ new _ _ “方法是新式类特有的方法,通常情况下, _ _ new _ _ 方法会创建返回cls(cls指代当前类)的实例,然后调用该类的” _ _ init _ _ “方法作为初始化方法,该方法接收这个实例(即self)作为自己的第一个参数,然后依次传入” _ _ new _ _ “方法中接收的位置参数和命名参数;但是,如果” _ _ new _ _ “没有返回cls(即当前类)的实例,那么当前类的” _ _ init _ _”方法是不会被调用的。