Python中__new__、__init__和__call__的用法

   __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的实例对象,同时还是可调用对象,因此可以像调用函数一样调用它。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值