需要了解__init__、__new__和__call__的流程
Posted
技术标签:
【中文标题】需要了解__init__、__new__和__call__的流程【英文标题】:need to understand the flow of __init__, __new__ and __call__ 【发布时间】:2012-10-09 21:56:17 【问题描述】:class Singleton(type):
def __init__(self, *args, **kwargs):
print 'calling __init__ of Singleton class', self
print 'args: ', args
print 'kwargs: ', kwargs
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
print 'running __call__ of Singleton', self
print 'args: ', args
print 'kwargs: ', kwargs, '\n\n'
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
class A(object):
__metaclass__ = Singleton
def __init__(self,a):
print 'in __init__ of A: ', self
self.a = a
print 'self.a: ', self.a
a=A(10)
b=A(20)
我从 Ben 对问题 Python's use of __new__ and __init__? 的回答中复制了这段代码,并对其进行了一些修改。但是,我不知道流量。尽管我从更高的层次上理解了这段代码的目的。但是,在内部它是如何工作的,我不太确定。
运行此代码时,我得到以下输出:-
calling __init__ of Singleton class <class '__main__.A'>
args: ('A', (<type 'object'>,), '__module__': '__main__', '__metaclass__': <class '__main__.Singleton'>, '__init__': <function __init__ at 0x01F9F7B0>)
kwargs:
running __call__ of Singleton <class '__main__.A'>
args: (10,)
kwargs:
in __init__ of A: <__main__.A object at 0x01FA7A10>
self.a: 10
running __call__ of Singleton <class '__main__.A'>
args: (20,)
kwargs:
我不明白__init__
和__call__
的args
和kwargs
是如何变得不同的。
在使用元类时,此链接 (What is a metaclass in Python?) 解释了如何使用 __new__
和函数作为元类。但是,我不明白__call__
是如何被使用的。
有人能解释一下流程吗?我的意思是,__new__
、__call__
、__init__
被调用的优先级以及谁调用它们?
【问题讨论】:
问题是,你想做什么? 我是许多 python 概念的新手。我正在尝试实现本在链接中的回答中提到的 Singleton 类:***.com/questions/674304/pythons-use-of-new-and-init。另外,在实现过程中,我想了解我编写的程序的内部流程。 你读过documentation吗?我强烈建议您完整阅读该页面。 是的,但是,它的解释不如 glglgl 在下面的回答中解释的那样。 【参考方案1】:您的代码不包含任何__new__
,因此对此几乎无话可说。
但是您创建了一个元类,该元类在创建类A
时被实例化。换句话说,A
类本身就是一个对象,也是它的元类Singleton
的一个实例。
那么让我们看看会发生什么:
A
的环境完成后(它的方法存在,它的字典也存在,...),类被创建为元类的一个实例。本质上,调用是
A = Singleton('A', (object,), <the dict>)
其中<the dict>
是包含类名称空间的字典(此处为:__module__
、__metaclass__
和__init__
)。
在对Singleton
的调用中,调用super(Singleton, self).__call__(*args, **kwargs)
会导致调用__new__
方法,该方法返回一个新实例,然后在该实例上调用.__init__
。
这就是发生这种情况的原因:
calling __init__ of Singleton class <class '__main__.A'>
args: ('A', (<type 'object'>,), '__module__': '__main__', '__metaclass__': <class '__main__.Singleton'>, '__init__': <function __init__ at 0x01F9F7B0>)
kwargs:
A
构造完成后,通过实例化来使用它:
a = A(10)
这调用A
。 A
是Singleton
的一个实例,所以Singleton.__call__
被调用——效果如下:
running __call__ of Singleton <class '__main__.A'>
args: (10,)
kwargs:
Singleton.__call__
调用type.__call__
,这调用A.__new__
和A.__init__
:
in __init__ of A: <__main__.A object at 0x01FA7A10>
self.a: 10
那你就做
b = A(20)
调用Singleton.__call__
:
running __call__ of Singleton <class '__main__.A'>
args: (20,)
kwargs:
这里super
调用被抑制并返回旧对象。
【讨论】:
如果我错了,请纠正我。在您的解释中:'On this call to Singleton, its __new__ is called and afterwards the .__init__ of the result.'
,通过单词 result
,您是否指的是 Singleton 类的隐式 __new__
方法的返回值(它将充当将创建类对象 A
的类) ?
还有,我的另一个问题是:你能举个例子,Singleton
类的__init__
中的kwargs
包含
以外的任何内容吗?
@GodMan 我已经改写了这句话。是的,Singleton.__call__
调用A.__new__
,它返回一个新实例,然后是新实例的__init__
。
对于您的第二个问题:不,超类将始终使用位置参数调用,因此 kwargs
始终保持为空。您甚至可以将 *args
更改为 name, bases, dict
,因为参数的数量也是固定的。
2 再次请求: 1. 对于Singleton.__call__ calls type.__call__, this calls A.__new__ and A.__init__
行,您能否分别为A.__new__ 和A.__init__ 提供参数 2. 对于调用:b = A(20)
,您已经写了Here the super call is suppressed and the old object is returned.
。是不是因为Singleton.__call__
返回了A
的现有实例,所以这里没有调用A.__init__
?以上是关于需要了解__init__、__new__和__call__的流程的主要内容,如果未能解决你的问题,请参考以下文章
Python:总是使用 __new__ 而不是 __init__?
由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别