Python中__init__、__new__与__call__方法的深度解析
本文深入解析Python中__init__、__new__和__call__三个核心魔法方法的执行顺序与作用。__new__负责创建实例,__init__负责初始化,两者参数需保持一致;__new__返回None则__init__不执行。__call__使实例可调用,常用于实现类装饰器或单例模式,结合Bottle框架源码展示实际应用场景。
前言
本文主要介绍Python中__init__、__new__和__call__方法的核心机制与应用场景,供开发者参考学习。
任何对象都经历从创建、使用到销毁的生命周期。在面向对象编程模型中,对象的创建、初始化、使用及垃圾回收由不同的方法阶段负责执行。
在定义类时,开发者最常使用__init__方法,而__new__和__call__较少涉及。本文旨在清晰阐述这三个方法的正确用法及具体应用场景。
本文不讨论新式类与老式类的区别,因为老式类属于Python2的概念,现已基本淘汰。Python3中所有类默认继承object,即为新式类,无需显式指定。本文代码均基于Python3环境。
__init__方法
__init__方法负责对象的初始化工作。在该方法执行前,对象实例实际上已经存在,否则初始化将无从谈起。示例如下:
# class A(object): python2 必须显示地继承object
class A:
def __init__(self):
print("__init__ ")
super(A, self).__init__()
def __new__(cls):
print("__new__ ")
return super(A, cls).__new__(cls)
def __call__(self): # 可以定义任意参数
print('__call__ ')
A()
输出
__new__ __init__
从输出结果可见,__new__方法先被调用并返回一个实例对象,随后__init__被调用。__call__方法在此处未被触发,将在后文单独讨论。
def __init__(self):
print("__init__ ")
print(self)
super(A, self).__init__()
def __new__(cls):
print("__new__ ")
self = super(A, cls).__new__(cls)
print(self)
return self
输出:
__new__ <__main__.A object at 0x1007a95f8> __init__ <__main__.A object at 0x1007a95f8>
从输出结果来看,__new__方法的返回值即为类的实例对象。该实例对象会作为self参数传递给__init__方法,以确保实例能被正确初始化。
如果__new__方法不返回值(即返回None),则__init__方法将不会被调用。这是因为实例未创建,调用初始化方法没有意义。此外,Python规定__init__只能返回None,否则将引发报错,读者可自行验证。
__init__方法常用于执行初始化工作,例如对实例对象的状态进行初始化:
def __init__(self, a, b): self.a = a self.b = b super(A, self).__init__()
另外,__init__方法中除self外的参数,必须与__new__方法中除cls外的参数保持一致或等效。
class B:
def __init__(self, *args, **kwargs):
print("init", args, kwargs)
def __new__(cls, *args, **kwargs):
print("new", args, kwargs)
return super().__new__(cls)
B(1, 2, 3)
# 输出
new (1, 2, 3) {}
init (1, 2, 3) {}
__new__方法
通常我们不会重写该方法,除非明确知晓其机制与适用场景。__new__作为构造函数用于创建对象,是一个专门生产实例对象的工厂函数。著名的单例设计模式即可通过此方法实现。在编写框架级代码时可能会用到它,例如微型Web框架Bottle中就有应用。
class BaseController(object): _singleton = None def __new__(cls, *a, **k): if not cls._singleton: cls._singleton = object.__new__(cls, *a, **k) return cls._singleton
这段代码出自 https://github.com/bottlepy/bottle/blob/release-0.6/bottle.py
这是通过__new__方法实现单例模式的一种方式:若实例已存在则直接返回,否则先创建实例再返回。当然,实现单例模式的方法不止一种,Python之禅指出:
There should be one-- and preferably only one --obvious way to do it.
用一种方法,最好是只有一种方法来做一件事。
__call__方法
关于__call__方法,需先了解“可调用对象”(callable)的概念。自定义函数、内置函数和类均属于可调用对象,即任何可将一对括号()应用于其上的对象均可称为可调用对象。可使用callable函数判断对象是否可调用。
若在类中实现__call__方法,其实例对象也将成为可调用对象。回到最初的例子:
a = A() print(callable(a)) # True
a是实例对象,同时也是可调用对象,因此可以像调用函数一样调用它。尝试:
a() # __call__
这体现了实例对象可作为可调用对象使用的特性。该特性适用于何种场景?结合类的特性来看,类可以存储数据(属性),而函数不行(闭包除外)。利用这一特性可实现基于类的装饰器,在类中记录状态。例如,以下示例用于记录函数被调用的次数:
class Counter: def __init__(self, func): self.func = func self.count = 0 def __call__(self, *args, **kwargs): self.count += 1 return self.func(*args, **kwargs) @Counter def foo(): pass for i in range(10): foo() print(foo.count) # 10
Bottle框架中也有__call__方法的使用案例,此外,stackoverflow上也有相关实践示例,推荐参考。若项目需要更高抽象度或框架级代码,这些高级特性往往能发挥重要作用。
总结
以上就是本文的全部内容,希望对大家的学习或工作有所帮助。如有疑问,欢迎留言交流,感谢支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









