python中的__new__, __init__和__call__函数用法详解

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是同一个对象。

一个对象从创建到被调用的大致流程:

  1. __new__是我们通过类名进行实例化对象时自动调用的;
  2. __init__是在每一次实例化对象之后调用的;
  3. __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的实例对象,同时也是一个可调用对象,因此可以像调用函数一样调用它。


参考:

《人人都懂设计模式:从生活中领悟设计模式》 罗伟富

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值