目录
- 前言
- 理解 __new__ 和 __init__ 的区别
- Python2中的类
- 处理不同的情况
- 简单总结:
- 参考文章
前言
文章内容为understanding-new-and-init的译文。
本文的目的是讨论Python中的 __new__ 和 __init__
__new__ 和 __init__ 的区别表现在:1、自身的区别 2、老式类和新式类在Python中的定义
理解 __new__ 和 __init__ 的区别
两者的主要区别是,__new__ 负责处理对象的创建,__init__ 负责处理对象的初始化。 在对象的实例化过程中,两个方法在定义不同时,工作方式略有不同。
Python2中的类
Python2中有新式类和老式类之分。老式类出现在Python3问世前, 定义时不继承基类 object
, 而是默认继承 type
,新式类则直接显示继承 object
。
Python2中的老式类:
class A: # -> inherits from 'type'
pass
class A: # -> inherits from 'type'
pass
Python2中的新式类
class A(object): # -> clearly inherits from 'object'
pass
class A(object): # -> clearly inherits from 'object'
pass
Python3中没有新式类和老式类的区分,所有的的类直接继承自 object
, 因此没有显示地指出 object
作为基类的必要。 object
基类的方法和属性,通用于所有新式类。
在文章的其它部分,我们将讨论 __new__ 和 __init__ 方法在两种情况下的区别: 它们如何表现和如何使用它们。
处理不同的情况
在深入实际的实现之前,你需要知道 __new__(类方法)接收 cls
作为第一个参数, __init__ 接收 self
作为第一个参数。 当调用 __new__ 时, 实际上你还没有获得一个实例, 所以此刻 self
并不存在。 而 __init__ 在 __new__ 创建并返回一个实例 之后调用, 此时实例已经创建可用,所以你可以传递使用 self
。
老式类中的 __new__ 和 __init__
老式类实际上没有 __new__ 方法,因为 __init__ 就是它们的构造函数,所以我们可以尝试:
class A:
def __new__(cls):
print "A.__new__ is called" # -> this is never called
A()
class A:
def __new__(cls):
print "A.__new__ is called" # -> this is never called
A()
在这种情况下, __new__ 方法不永远不会被执行, 因为它不是老式类目标函数。
如果我们使用重写 __init__ 的方式来替代:
class A:
def __init__(self):
print "A.__init__ called"
A()
class A:
def __init__(self):
print "A.__init__ called"
A()
输出将会是:
A.__init__ called
A.__init__ called
现在让我们尝试让 __init__ 返回一个值:
class A:
def __init__(self):
return 29
A()
class A:
def __init__(self):
return 29
A()
这会导致一个异常:
TypeError: __init__() should return None
TypeError: __init__() should return None
这意味着在实例化老式类的时,我们实际上不能控制它的返回。
新式类中的 __new__ 和 __init__
新式类可以让开发者同时重写 __new__ 和 __init__ ,两者有不同的用处, __new__(构造函数) 单一的创建对象,__init__ (初始化函数) 初始化这个对象。
让我们看下它们的执行顺序:
class A(object): # -> don't forget the object specified as base
def __new__(cls):
print "A.__new__ called"
return super(A, cls).__new__(cls)
def __init__(self):
print "A.__init__ called"
A()
class A(object): # -> don't forget the object specified as base
def __new__(cls):
print "A.__new__ called"
return super(A, cls).__new__(cls)
def __init__(self):
print "A.__init__ called"
A()
输出如下:
A.__new__ called
A.__init__ called
A.__new__ called
A.__init__ called
你也许想要知道 __new__ 和 __init__ 在何处被调用,我能告诉你的是,在调用类名时(实例化期间) __new__ 被自动调用。而 __init__ 则在每次 __new__ 返回类的实例时调用,并将返回的实例作为 self
参数传递给 __init__。 即使你将创建的实例保存成全局或者静态对象, 并且在每次调用 __new__后返回这个对象,__init__依然每次会被调用。
知道这个意味着如果我们在 __new__ 忽略调用基类的 super(A, cls).__new__(cls)
,会导致 __init__ 不被执行。让我们看看下面这种情况:
class A(object):
def __new__(cls):
print "A.__new__ called"
def __init__(self):
print "A.__init__ called" # -> is actually never called
print A()
class A(object):
def __new__(cls):
print "A.__new__ called"
def __init__(self):
print "A.__init__ called" # -> is actually never called
print A()
输出结果为:
A.__new__ called
None
A.__new__ called
None
很明显,当我们在构造器中不返回东西时,实例被认为是 None
。
想象下如果我们尝试让 __new__ 返回一些东西,会发生什么事情。
class A(object):
def __new__(cls):
print "A.__new__ called"
return 29
print A()
class A(object):
def __new__(cls):
print "A.__new__ called"
return 29
print A()
输出结果为:
A.__new__ called
29
A.__new__ called
29
让我们看看当我们尝试让 __init__ 返回时,会发生什么:
class A(object):
def __init__(self):
print "A.__init__ called"
return 33 # -> TypeError: __init__ should return None
A()
class A(object):
def __init__(self):
print "A.__init__ called"
return 33 # -> TypeError: __init__ should return None
A()
触发了异常:
TypeError: __init__ should return None
TypeError: __init__ should return None
这主要是因为调用 __init__ 的处理程序引发了 TypeError
异常,从 __init__ 返回东西没有意义,因为它的主要功能是更改新创建实例的状态。
看起来新式类给我们提供了更多的灵活性,允许我们在对象创建和初始化的前后做任何操作,并且允许我们控制实例化时返回的内容。
考虑到这一点,让我们在 __new__ 中返回另一个类的实例。
首先,我们定义一个待用的类:
class Sample(object):
def __str__(self):
return "SAMPLE"
class Sample(object):
def __str__(self):
return "SAMPLE"
然后, 我们定义一个重写 __new__ 的类:
class A(object):
def __new__(cls):
return Sample()
class A(object):
def __new__(cls):
return Sample()
这个也可以写成如下形式:
class A(object):
def __new__(cls):
return super(A, cls).__new__(Sample)
class A(object):
def __new__(cls):
return super(A, cls).__new__(Sample)
接着调用:
print A()
print A()
输出为:
SAMPLE
简单总结:
Python3中 __new__ 负责对象的创建,__init__ 负责对象的初始化。