疑惑 提出问题python
前天同事问我一个问题,为何这个脚本中的没有调用A 的__init__。脚本以下:学习
1 class A(object): 2 def __init__(self, *args, **kwargs): 3 print "Call init from %s" %self.__class__ 4 5 def __new__(cls, *args, **kwargs): 6 obj = object.__new__(cls, *args, **kwargs) 7 print "Call new from %s" %obj.__class__ 8 return obj 9 10 11 class B(object): 12 def __init__(self, *args, **kwargs): 13 print "Call init from %s" %self.__class__ 14 15 def __new__(cls, *args, **kwargs): 16 obj = object.__new__(A, *args, **kwargs) 17 print "Call new from %s" %obj.__class__ 18 return obj 19 20 b = B()
其实我也比较奇怪,这个脚本写的比较奇怪,class B的的__new__返回了A的实例。也只是只执行了B的__new__方法,并无执行A的__init__方法。spa
深刻 迷失debug
遇到这个问题:调试
要深刻首先查看了一下代码的编译后的python指令,查看B,是B的__init__方法的指令,code
如上图,为了具体查看B()方法是如何调用,就添加了一个方法test_B。B()显示仅仅是两条指令blog
LOAD_GLOBALit
CALL_FUNCTIONio
查看Python源代码,到编译
PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
{
ternaryfunc call;
if ((call = func->ob_type->tp_call) != NULL) {
PyObject *result;
if (Py_EnterRecursiveCall(" while calling a Python object"))
return NULL;
result = (*call)(func, arg, kw);
**************看到这里的时候有点迷失了,不知道tp_call是个什么东西了,不肯定由typeobject来操做
(这个必须进行反省由于tp_call已已经明确了他来自哪里)***************
调试 问题解决
最后使出了,大招对Python源代码进行调试,在Linux上编译python源代码加上参数--with-debug, 而后执行gdb -ex r --args python test.py
,
在call_function,do_call,PyObject_Call 执行到以后,打上断点。看到他运行到了
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
obj = type->tp_new(type, args, kwds);
if (obj != NULL) {
if (!PyType_IsSubtype(obj->ob_type, type))
return obj;
,这个时候我再去看代码。发现哪里已经写好注释了:
/* If the returned object is not an instance of type,
it won't be initialized. */
好吧,很明确了了。没有产生和class类型一致的instance,就不会进行初始化。即调用__init__。
问题解决了。。也学习了
要问我怎么知道在那个地方打断点,由于我已经看过了代码,只是理解没有那么深。