python中的__new__, __init__和__call__函数用法详解
1. 开门见山
首先要对这三个函数有一个直观感性的认识:
- __new__负责类中对象的创建,而__init__负责对创建的对象进行初始化;
- __new__是一个类方法,而__init__和__call__是对象方法;
- __call__用于声明这个类的对象时可调用的(callable)
代码示例:
class ClassA:
def __new__(cls):
print('ClassA.__new__')
return super().__new__(cls)
def __init__(self) -> None:
print('ClassA.__init__')
def __call__(self, *args):
print('ClassA.__call__ args:', args)
a = ClassA() # a是ClassA的实例化对象
a('args1', 'args2') # 对a实例进行调用
执行结果:
ClassA.__new__
ClassA.__init__
ClassA.__call__ args: ('args1', 'args2')
从结果可以看出,创建一个对象时会先调用__new__方法,在调用__init__方法
。__new__方法需要返回一个该类的实例化对象,__init__方法用来为实例对象属性赋值,不能有返回值。__call__方法使得这个类的对象本身可以进行调用。
2. __new__方法:
__new__方法是构造函数,其参数接收一个类名,默认使用表示本类的cls。它负责对象的创建,需要返回一个实例。
如果__new__方法不返回实例:
class ClassB:
def __new__(cls: type):
print('ClassB.__new__')
# return super().__new__(cls) # 不返回对象
def __init__(self):
print('ClassB.__init__')
b = ClassB()
print(b)
执行结果:
ClassB.__new__
None
可知,当__new__构造函数没有返回对象时,b对象为None。
如果我们在__new__中返回一个其他类的对象可行吗?
class ClassB:
def __new__(cls: type):
print('ClassB.__new__')
return 3.0
def __init__(self):
print('ClassB.__init__')
b = ClassB()
print(b)
type(b)
执行结果:
ClassB.__new__
3.0
float
这意味着。我们完全可以通过重写__new__方法来控制类对象的实例化过程,甚至可以在ClassB的__new__方法中创建ClassA的对象:
class ClassB:
def __new__(cls):
print('ClassB.__new__')
return super().__new__(ClassA)
# return ClassA() # 也可用这种写法
def __init__(self):
print('ClassB.__init__')
b = ClassB()
print(b)
type(b)
执行结果:
ClassB.__new__
<__main__.ClassA object at 0x000002110FF40C88>
__main__.ClassA
注意 :在正常使用时,一定要杜绝此类写法,否则在出现问题时将很难跟踪。
3. __init__方法:
__init__方法是一个初始化函数,负责对__new__实例化的对象进行初始化,即负责对象状态的更新和属性的设置。它不允许有返回值。
如果在__init__中添加返回值,则会直接报错:
class ClassC:
def __init__(self):
print('ClassC.__init__')
return 3.0
c = ClassC()
print(c)
报错:
TypeError: __init__() should return None, not 'float'
__init__方法除了self定义的参数,其他参数都必须和__new__方法中除了cls参数为的参数保持一致或者等效:
class ClassC:
def __init__(self, *args, **kwargs):
print('init: ', args, kwargs)
def __new__(cls, *args, **kwargs):
print('new: ', args, kwargs)
return super().__new__(cls)
c = ClassC('args1', 'args2', a=1, b=2)
执行结果:
new: ('args1', 'args2') {'a': 1, 'b': 2}
init: ('args1', 'args2') {'a': 1, 'b': 2}
4. 对象的创建过程:
为了清楚地了解一个对象的创建过程,我们先看一个示例:
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 0x000002110FF40518>
ClassD.__init__
<__main__.ClassD object at 0x000002110FF40518>
从结果可以看出__new__中返回的self对象和__init__中调用的self是同一个对象。
一个对象从创建到被调用的大致流程:
- __new__是我们通过类名进行实例化对象时自动调用的;
- __init__是在每一次实例化对象之后调用的;
- __new__方法创建一个实例之后返回这个实例对象,并将其传递给__init__方法的self参数。
5. __call__方法:
在介绍__call__之前,我们先来了解一下callable
内建函数:
如果callable的对象参数显示为可调用,则返回True,否则返回False。如果返回True,则调用仍可能失败,但如果返回False,则调用必不可能成功。
我们平时定义的函数、内置函数和类都属于可调用对象,但凡是可以使用‘()’放在对象之后使用的,都可以称之为可调用对象。callable返回True的对象,我们就可以像使用函数一样使用它。
def func_test(name):
print('This is a test function, name: ', name)
print(callable(filter))
print(callable(max))
print(callable(object))
print(callable(func_test))
var = "Test"
print(callable(var))
func_test('python')
执行结果:
True
True
True
True
False
This is a test function, name: python
__call__的作用就是声明一个对象是可调用的。即实现__call__方法之后,用callable调用这个类的对象
时,结果为true。
class ClassE:
pass
e = ClassE()
print(callable(e))
print('-' * 30)
class ClassF:
def __call__(self, *args):
print('This is __call__ function, args: ', args)
f = ClassF()
print(callable(f))
f('args1', 'args2')
执行结果:
False
------------------------------
True
This is __call__ function, args: ('args1', 'args2')
f是ClassF的实例对象,同时也是一个可调用对象,因此可以像调用函数一样调用它。
参考:
《人人都懂设计模式:从生活中领悟设计模式》 罗伟富