class MyType(type):
def __init__(self, what, bases=None, dict=None):
print('call myType.__init__()') #语句 1
super().__init__(what, bases, dict)
def __new__(cls, name, bases, attrs):
print("call MyType.__new__()") #语句 2
return type.__new__(cls, name, bases, attrs)
def __call__(self, *args, **kwargs):
print("MyType.__call__")
class Foo(object, metaclass=MyType):
def __init__(self, name=None):
self.name = name
print("Foo self.name=", self.name)
def __new__(cls, *args, **kwargs):
print("Foo.__new__ cls=", cls)
return(object.__new__(cls, *args, **kwargs))
def __call__(self, cls):
print("Foo.__call__ cls=", cls)
if name == 'main':
print("---------test---------") #语句 3
obj=Foo() #语句 4
上面代码在 PYTHON3.6 中输出如下:
call MyType.new() #语句 2 的输出
call myType.init() #语句 1 的输出
---------test---------
MyType.call #语句 4 的输出
请问,为何语句 4 “ obj=Foo()” 会导致__call__方法的执行? 我看了这篇博文 python.jobbole.com/83747/ 博文的“ 5.call”小节写了这段话:“注:构造方法的执行是由创建对象触发的,即:对象=类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象()或者类()()”
看了这段话后再结合上面这个程序,我就觉得有问题,obj=Foo()这个语句应该是博文中的 对象=类名() 这个形式,所以不应该调用 Foo.call()方法才对啊? 关于这个观点,我还有一个例子可以说明,比如下面这段代码和对应的输出,请注意语句 1 就是一个把对象实例化的语句,这个语句并没有调用类的__call__()方法,所以两个例子出现了矛盾,同样是类的实例化,上面的程序调用了类的 call 方法,下面的却没有:
class Deco:
def __init__(self,func):
self.func=func
print("__init__执行完毕。func=",self.func)
def __call__(self,*arg,**arg2):
print("开始执行__call__。")
self.func('abc')
print(self,arg,arg2)
class MyCls():
@Deco
def myFunc(self):
print('this is my work arg is %s'%self)
mycls=MyCls()
deco=Deco(mycls.myFunc)
代码输出如下: __init__执行完毕。func= <function MyCls.myFunc at 0x01C49AE0>
__init__执行完毕。func= <main.Deco object at 0x01C4B190>
1
lolizeppelin 2017-07-19 22:23:31 +08:00
初学不要去关心 new 之类的黑魔法 先避开
装饰器也尽量避开不要折腾 装饰器只是个套娃语法糖, 具体工作的时候涉及到闭包还有描述器之类的黑魔法 等你比较熟了再回来弄这个 |
2
lrxiao 2017-07-19 23:11:08 +08:00
你自己写的 metaclass 的__call__啊
|
3
yufpga 2017-07-19 23:11:16 +08:00
注意到 Foo 中的 metaclass 了么,这里面涉及到元类,这个东西一时半会讲不清楚(限于自身水平原因),你可以去掉 metaclass 部分,打印一下 obj.__class__, 自己慢慢体会下
|
4
saximi OP @lrxiao 为何写了 metaclass 的__call__就会导致实例化时的调用呢,我也看过一些介绍 metaclass 的博文,但是没有针对这个问题作出解释
|
5
saximi OP @yufpga 去掉 metaclass 的话,确实就不会发生调用 Foo 类的__call__方法了,但是就是不明白为何加上 metaclass 就会如此呢
|
6
raptium 2017-07-19 23:49:19 +08:00 via iPad
https://stackoverflow.com/questions/6966772/using-the-call-method-of-a-metaclass-instead-of-new
感觉就是在做蠢事,metaclass 上定义了 __call__,导致根本没法通过()实例化了。 |
7
lrxiao 2017-07-20 00:17:02 +08:00
@saximi 因为 class 是 metaclass 的实例 相当于你这个 Foo 已经是 MyType(....) 出来的 就有 MyType.__call__
但是装饰器之间没有实例关系 不调用__call__ |