__new__、__init__和__call__都是Python中的魔法函数,我们先对它们有个感性的认识:
- __new__负责对象的创建,而__init__负责对象的初始化;
- __new__是一个类方法,而__init__和__call__是一个对象方法;
- __call__声明这个类的对象是可调用的
有如下示例代码:
class ClassA:
def __new__(cls):
print("ClassA.__new__")
return super().__new__(cls)
def __init__(self):
print("ClassA.__init__")
def __call__(self, *args):
print("ClassA.__call__ args:", args)
a = ClassA()
a("arg1", "arg2")
输出结果如下:
ClassA.__new__
ClassA.__init__
ClassA.__call__ args: ('arg1', 'arg2')
__new__函数
__new__是构造函数,负责对象的创建,它需要返回一个实例。有如下示例代码:
class ClassB:
def __new__(cls):
print("ClassB.__new__")
def __init__(self):
print("ClassB.__init__")
b = ClassB()
print(b)
输出结果如下:
ClassB.__new__
None
这里b被认为None,因为我们没有在构造函数中返回任何对象。如果我们在___new___返回一个其它的对象,会出现什么情况?有如下示例代码:
class ClassB:
def __new__(cls):
print("ClassB.__new__")
return 3.0
def __init__(self):
print("ClassB.__init__")
b = ClassB()
print(b)
输出结果如下:
ClassB.__new__
3.0
这意味我们完全可以通过重写___new___函数来控制类对象的实例化过程。通常情况下,我们会在___new___函数返回super().__new__(cls)
,这样才能调用类本身,示例代码如下:
class ClassB:
def __new__(cls):
print("ClassB.__new__")
return super().__new__(cls)
def __init__(self):
print("ClassB.__init__")
b = ClassB()
print(b)
输出结果如下:
ClassB.__new__
ClassB.__init__
<__main__.ClassB object at 0x00000213BD892748>
__init__函数
__init__是一个初始化函数,负责对__new__实例化的对象进行初始化,它不允许有返回值。示例代码如下:
class ClassC:
def __init__(self):
print("ClassC.__init__")
return 3.0
c = ClassC()
print(c)
返回结果如下:
Traceback (most recent call last):
File "my_test.py", line 8, in <module>
c = ClassC()
TypeError: __init__() should return None, not 'float'
ClassC.__init__
_init__函数除了self定义的参数,其它参数都必须与___new__函数中除了cls参数外的参数保持一致。为了弄清楚一个对象的创建过程,有如下示例代码:
class ClassD:
def __new__(cls):
print("ClassD.__new__")
self = super().__new__(cls)
print(self)
return self
def __init__(self):
print("ClassD.__init__")
print(self)
d = ClassD()
输出结果如下:
ClassD.__new__
<__main__.ClassD object at 0x0000025773012780>
ClassD.__init__
<__main__.ClassD object at 0x0000025773012780>
从中我们可以知道:
- __new__函数创建一个实例之后返回这个实例对象,并将其传递给__init__函数的self参数
- _init__函数的调用在___new__函数之后
__call__函数
__call__函数的作用就是声明这个类的对象是可调用的(callable)。当有一个对象时,例如object(*args, **kwargs)
语句在Python中等价于object.__call__(*args, **kwargs)
。
未在类中声明__call__函数,该类的对象是不可调用的,如下代码:
class ClassE:
pass
e = ClassE()
print(callable(e))
输出结果为:
False
在类中声明__call__函数,该类的对象是可调用的,如下代码:
class ClassE:
def __call__(self, *args, **kwargs):
print("__call__ function: ", args)
e = ClassE()
print(callable(e))
e("arg1", "arg2")
输出结果如下:
True
__call__ function: ('arg1', 'arg2')
e是ClassE的实例对象,同时还是可调用对象,因此可以像调用函数一样调用它。