Skip to content

Instantly share code, notes, and snippets.

@ruoyu0088
Created June 4, 2017 09:06
Show Gist options
  • Save ruoyu0088/405d1c09f948c4dd1072bd57ca467f05 to your computer and use it in GitHub Desktop.
Save ruoyu0088/405d1c09f948c4dd1072bd57ca467f05 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# super"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 改变描述器的搜索途径"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`super`是一个类型,其对应的C语言结构体为`PySuper_Type`。其主要目的是调用父类中定义的方法。创建`super`对象需要两个参数:`type_`和`obj`,其中`type_`是一个类型对象,`obj`对象是`type_`类型的一个实例。当访问`super`对象的属性时,将在`type_.__mro__`中位于`type(obj)`之后的类型对象中搜索描述器(Descriptor)。其实现代码在`super_getattro()`中。下面通过一个例子解释`super`的属性搜索行为:"
]
},
{
"cell_type": "code",
"execution_count": 76,
"metadata": {},
"outputs": [],
"source": [
"class A:\n",
" def func(self):\n",
" print(\"A.func\", self.name)\n",
" \n",
"class B(A):\n",
" def __init__(self, name):\n",
" self.name = name\n",
" \n",
" def func(self):\n",
" print(\"B.func\", self.name)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`b.func`将首先在`b`的类型`B`的`__dict__`中搜索`\"func\"`,由于`B.__dict__[\"func\"]`是一个函数对象,函数对象具有`__get__`属性,因此`b.func`得到的是一个`bound method`对象,该对象对`b`和`B.__dict__[\"func\"]`包装,调用它时相当与调用`B.__dict__[\"func\"](b)`。这就是Python实现方法调用的方式。"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<bound method B.func of <__main__.B object at 0x000000E562CED208>>\n",
"B.func b\n"
]
}
],
"source": [
"b = B(\"b\")\n",
"print(b.func)\n",
"b.func()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面来看`super`是如何改变属性的搜索路径的。`B.__mro__`中有三个元素,其中`A`和`object`位于`B`之后,因此获取`super`对象`sb`的`func`属性时,将依次检查`A`和`object`的`__dict__`中是否有名为`func`的描述器,由于在`A`中找到了,因此将得到调用它的`__get__()`所得到的`bound method`对象。"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)\n",
"A.func b\n"
]
}
],
"source": [
"sb = super(B, b)\n",
"print(B.__mro__)\n",
"\n",
"sb.func()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面分别查看`b.func`和`sb.func`这两个`bound method`对象中`__func__`属性的函数全名:"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"B.func A.func\n"
]
}
],
"source": [
"print(b.func.__func__.__qualname__, sb.func.__func__.__qualname__)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Python3中的super"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`super`通常用于调用父类的方法,然而在Python 2中由于使用`super`使需要传递类对象和实例对象,使得调用`super`的语句不简洁,并且一旦需要修改类名,所有的`super`调用都需要修改。在Python 3中这一点得到了改进,例如下面的程序中在`B.func`中使用`super`时,不需要传递任何参数。"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A.func b\n",
"B.func b\n"
]
}
],
"source": [
"class A:\n",
" def func(self):\n",
" print(\"A.func\", self.name)\n",
" \n",
"class B(A):\n",
" def __init__(self, name):\n",
" self.name = name\n",
" \n",
" def func(self):\n",
" super().func()\n",
" print(\"B.func\", self.name)\n",
" \n",
"b = B(\"b\")\n",
"b.func()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面我们分析`super()`是如何得到`B`和`self`这两个对象的。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 获取`self`参数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在类中定义的函数,其第一个参数一定是实例对象,因此只需要找到第一个参数所指向的对象即可。Python中每层函数调用都会创建对应的`frame`(与`PyFrameObject`结构体对应)对象。其最后一个字段`f_localsplus`是可变长的数组:\n",
"\n",
"```c\n",
"PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */\n",
"```\n",
"\n",
"这个数组中的头一个元素就是传递给与其对应的函数的第一个参数。因此可以在`super`对象的初始化函数`super_init()`中找到这样的语句:\n",
"\n",
"```c\n",
"if (type == NULL) {\n",
" /* Call super(), without args -- fill in from __class__\n",
" and first local variable on the stack. */\n",
" PyFrameObject *f;\n",
" PyCodeObject *co;\n",
" Py_ssize_t i, n;\n",
" f = PyThreadState_GET()->frame;\n",
" /* ... */\n",
" obj = f->f_localsplus[0];\n",
"}\n",
"```\n",
"\n",
"即若没有传递类型对象,则把当前的`frame`对象的`f_localsplus`数组中的第一个元素作为实例对象。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面通过程序验证上述事实。`get_frame_localsplus(frame, idx)`用于获取`frame`中`f_localsplus`字段的第`idx`元素。关于其具体实现,请读者参考`frame`相关的章节。"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import ctypes\n",
"import inspect\n",
"\n",
"def get_frame_localsplus(frame, idx):\n",
" code = frame.f_code\n",
" extras = code.co_nlocals + len(code.co_cellvars) + len(code.co_freevars) + code.co_stacksize\n",
" addr = id(frame) + frame.__sizeof__() - (extras - idx) * ctypes.sizeof(ctypes.c_ssize_t)\n",
" return ctypes.cast(addr, ctypes.POINTER(ctypes.c_ssize_t))[0]\n",
"\n",
"class A:\n",
" def first_locals_is_self(self):\n",
" frame = inspect.currentframe()\n",
" first_ref = get_frame_localsplus(frame, 0)\n",
" return first_ref"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在`A.first_locals_is_self`中,首先通过`inspect.currentframe()`获得当前运行中的`frame`对象,然后调用`get_frame_localsplus()`获得其中`f_localsplus`字段的第0个元素。下面验证这第0个元素就是实例`a`的地址:"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"985205208064 985205208064\n"
]
}
],
"source": [
"a = A()\n",
"print(id(a), a.first_locals_is_self())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 获取当前的类"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"为了在`super_init()`中获取包含正在被调用的函数的类,Python 3对编译器进行了一些改动。为了理解这些改动,我们先看看类是如何被创建的。当Python编译器遇到`class`关键字定义类时,将在一个新的运行环境(字典)中运行`class`中的代码。然后调用`type()`创建类型对象。下面是与`class`关键字等效的代码。"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<__main__.A object at 0x000000E562D04668>\n"
]
}
],
"source": [
"env = {}\n",
"\n",
"exec(\"\"\"\n",
"def func(self):\n",
" print(self)\n",
"\"\"\", env)\n",
"\n",
"A = type(\"A\", (object,), env)\n",
"\n",
"a = A()\n",
"a.func()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"由上述的过程可知,当类中的方法函数定义时,类型对象还未被创建,因此Python 3在类型对象创建之后,对其中包含`super`的函数进行处理。为这些函数创建`__closure__`属性,在其中使用`__class__`引用该函数所属的类。\n",
"\n",
"下面看一个例子:"
]
},
{
"cell_type": "code",
"execution_count": 78,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class A:\n",
" \n",
" def func_with_super(self):\n",
" super\n",
" \n",
" def func_no_super(self):\n",
" pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`A.func_with_super()`中引用了`super`符号,因此Python编译器会在创建类型`A`时,为该函数添加一个名为`__class__`的`freevar`变量,该变量引用`__closure__[0].cell_contents`,即类型对象`A`:"
]
},
{
"cell_type": "code",
"execution_count": 79,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('__class__',)\n",
"<class '__main__.A'>\n"
]
}
],
"source": [
"print(A.func_with_super.__code__.co_freevars)\n",
"print(A.func_with_super.__closure__[0].cell_contents)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在`A.func_no_super()`中没有引用`super`符号,因此其`__closure__`为空:"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [],
"source": [
"A.func_no_super.__closure__"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"注意Python编译器只检查函数中是否有`super`的引用,而不关心它实际内容是什么。在下面的例子中`func_with_mysuper`的`__closure__`为空,而`func_with_super`的`__closure__`则有类型`B`的引用。"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"None\n",
"(<cell at 0x000000E562C5DF18: type object at 0x000000E566222AA8>,)\n",
"(<cell at 0x000000E562C5DF18: type object at 0x000000E566222AA8>,)\n"
]
}
],
"source": [
"mysuper, super = super, \"something\"\n",
"\n",
"class B:\n",
" def func_with_mysuper(self):\n",
" mysuper\n",
" \n",
" def func_with_super(self):\n",
" super\n",
" \n",
" def func_with_super2(self):\n",
" super = 2\n",
" super\n",
" \n",
"print(B.func_with_mysuper.__closure__) \n",
"print(B.func_with_super.__closure__)\n",
"print(B.func_with_super2.__closure__) \n",
"super = mysuper"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"相关的代码:\n",
"\n",
"* `symtable.c`中`case Name_kind:`部分检查是否存在`super`的引用。如果存在则添加一个`__class__`引用。\n",
"* `compile.c`中`if (u->u_ste->ste_needs_class_closure) {`的部分检查函数是否存在`__class__`引用,如果存在,则产生相应的代码。\n",
"* 创建类时会调用内置函数`__build_class__()`执行创建类的代码。\n",
"* 在创建类的代码中可以找到创建`__class__`的语句。"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 2 0 LOAD_BUILD_CLASS\n",
" 1 LOAD_CONST 1 (<code object A at 0x000000B9468434B0, file \"<ipython-input-1-794cc6fd2a02>\", line 2>)\n",
" 4 LOAD_CONST 2 ('A')\n",
" 7 MAKE_FUNCTION 0\n",
" 10 LOAD_CONST 2 ('A')\n",
" 13 CALL_FUNCTION 2 (2 positional, 0 keyword pair)\n",
" 16 STORE_FAST 0 (A)\n",
"\n",
" 5 19 LOAD_FAST 0 (A)\n",
" 22 RETURN_VALUE\n"
]
}
],
"source": [
"def test():\n",
" class A:\n",
" def func(self):\n",
" super\n",
" return A\n",
"\n",
"import dis\n",
"dis.dis(test)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"上面的代码动态地创建了一个函数,并且把它作为参数传递给了`__build_class__()`函数。这个被创建的函数的代码如下:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 2 0 LOAD_NAME 0 (__name__)\n",
" 3 STORE_NAME 1 (__module__)\n",
" 6 LOAD_CONST 0 ('test.<locals>.A')\n",
" 9 STORE_NAME 2 (__qualname__)\n",
"\n",
" 3 12 LOAD_CLOSURE 0 (__class__)\n",
" 15 BUILD_TUPLE 1\n",
" 18 LOAD_CONST 1 (<code object func at 0x000000B946879270, file \"<ipython-input-1-794cc6fd2a02>\", line 3>)\n",
" 21 LOAD_CONST 2 ('test.<locals>.A.func')\n",
" 24 MAKE_CLOSURE 0\n",
" 27 STORE_NAME 3 (func)\n",
" 30 LOAD_CLOSURE 0 (__class__)\n",
" 33 RETURN_VALUE\n"
]
}
],
"source": [
"class_code = test.__code__.co_consts[1]\n",
"dis.dis(class_code)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以看到函数的返回值是一个`cell`对象。在`__build_class__`的代码中,如果`cell`变量通过`PyCell_Check(cell)`检查,则调用`PyCell_Set(cell, cls)`将该`cell`的内容设置为被创建的类:\n",
"\n",
"```c\n",
"cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,\n",
" NULL, 0, NULL, 0, NULL, 0, NULL,\n",
" PyFunction_GET_CLOSURE(func));\n",
"if (cell != NULL) {\n",
" PyObject *margs;\n",
" margs = PyTuple_Pack(3, name, bases, ns);\n",
" if (margs != NULL) {\n",
" cls = PyEval_CallObjectWithKeywords(meta, margs, mkw);\n",
" Py_DECREF(margs);\n",
" }\n",
" if (cls != NULL && PyCell_Check(cell))\n",
" PyCell_Set(cell, cls);\n",
" Py_DECREF(cell);\n",
"}\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"B.func_with_super.__closure__"
]
},
{
"cell_type": "code",
"execution_count": 195,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import sys\n",
"import dis\n",
"import inspect\n",
"import ctypes"
]
},
{
"cell_type": "code",
"execution_count": 329,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def get_object(addr):\n",
" ctypes.cast(addr, ctypes.py_object).value\n",
"\n",
"def get_frame_localsplus(frame):\n",
" code = frame.f_code\n",
" extras = code.co_nlocals + len(code.co_cellvars) + len(code.co_freevars) + code.co_stacksize\n",
" addr_localsplus = id(frame) + frame.__sizeof__() - extras * ctypes.sizeof(ctypes.c_ssize_t)\n",
" arr_localsplus = (ctypes.c_ssize_t * extras).from_address(addr_localsplus)\n",
" return list(arr_localsplus)\n",
"\n",
"code_attrs = \"co_argcount co_stacksize co_nlocals co_cellvars co_freevars co_varnames\"\n",
"\n",
"def local_counts(code):\n",
" for attr in code_attrs.split():\n",
" print(attr, getattr(code, attr))"
]
},
{
"cell_type": "code",
"execution_count": 279,
"metadata": {},
"outputs": [],
"source": [
"class A:\n",
" def first_locals_is_self(self):\n",
" frame = inspect.currentframe()\n",
" addrs = get_frame_localsplus(frame)\n",
" return addrs\n",
" \n",
" def call_super(self):\n",
" super()\n",
" \n",
" def no_super(self):\n",
" pass"
]
},
{
"cell_type": "code",
"execution_count": 280,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"149438360\n",
"[149438360, 121862680, 0, 149344600, 121862680]\n"
]
}
],
"source": [
"a = A()\n",
"print(id(a))\n",
"print(a.first_locals_is_self())"
]
},
{
"cell_type": "code",
"execution_count": 282,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"co_argcount 1\n",
"co_stacksize 1\n",
"co_nlocals 1\n",
"co_cellvars ()\n",
"co_freevars ()\n",
"co_varnames ('self',)\n"
]
}
],
"source": [
"local_counts(A.no_super.__code__)"
]
},
{
"cell_type": "code",
"execution_count": 283,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"co_argcount 1\n",
"co_stacksize 1\n",
"co_nlocals 1\n",
"co_cellvars ()\n",
"co_freevars ('__class__',)\n",
"co_varnames ('self',)\n"
]
}
],
"source": [
"local_counts(A.call_super.__code__)"
]
},
{
"cell_type": "code",
"execution_count": 286,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"__main__.A"
]
},
"execution_count": 286,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.call_super.__closure__[0].cell_contents"
]
},
{
"cell_type": "code",
"execution_count": 296,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('__class__',)\n",
"<cell at 0x0000000008E54888: empty>\n",
"<cell at 0x0000000008E54888: type object at 0x000000000724D138>\n",
"True\n"
]
}
],
"source": [
"class B: \n",
" def call_super(self):\n",
" super()\n",
" \n",
" print(call_super.__code__.co_freevars)\n",
" print(call_super.__closure__[0])\n",
" \n",
"print(B.call_super.__closure__[0])\n",
"print(B.call_super.__closure__[0].cell_contents is B)"
]
},
{
"cell_type": "code",
"execution_count": 297,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class C:\n",
" def has___class__(self):\n",
" print(__class__)"
]
},
{
"cell_type": "code",
"execution_count": 298,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('__class__',)"
]
},
"execution_count": 298,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"C.has___class__.__code__.co_freevars"
]
},
{
"cell_type": "code",
"execution_count": 300,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 300,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"C.has___class__.__closure__[0].cell_contents is C"
]
},
{
"cell_type": "code",
"execution_count": 304,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 304,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"my_super = super\n",
"\n",
"class D:\n",
" def use_my_super(self):\n",
" return my_super()\n",
" \n",
"D.use_my_super.__code__.co_freevars"
]
},
{
"cell_type": "code",
"execution_count": 326,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def outer_func(__class__):\n",
" \n",
" def inner_func1(self):\n",
" return super()\n",
" \n",
" def inner_func2(self):\n",
" __class__\n",
" return my_super()\n",
" \n",
" return inner_func1, inner_func2"
]
},
{
"cell_type": "code",
"execution_count": 328,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<super: <class 'D'>, <D object>>\n",
"<super: <class 'D'>, <D object>>\n"
]
}
],
"source": [
"f1, f2 = outer_func(D)\n",
"d = D()\n",
"print(f1(d))\n",
"print(f2(d))"
]
},
{
"cell_type": "code",
"execution_count": 353,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class E:\n",
" def nested_func_ng(self, a, b):\n",
" def func():\n",
" return super()\n",
" return func\n",
" \n",
" def nested_func_ok(self, a, b):\n",
" sup = super()\n",
" def func():\n",
" return sup\n",
" return func"
]
},
{
"cell_type": "code",
"execution_count": 354,
"metadata": {},
"outputs": [
{
"ename": "RuntimeError",
"evalue": "super(): no arguments",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mRuntimeError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-354-cd32dd100183>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0me\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mE\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnested_func_ng\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m<ipython-input-353-75a6447c7031>\u001b[0m in \u001b[0;36mfunc\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mnested_func_ng\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mb\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 5\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mRuntimeError\u001b[0m: super(): no arguments"
]
}
],
"source": [
"e = E()\n",
"e.nested_func_ng(1, 2)()"
]
},
{
"cell_type": "code",
"execution_count": 355,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<super: __main__.E, <__main__.E at 0x8ea8da0>>"
]
},
"execution_count": 355,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"e.nested_func_ok(1, 2)()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import inspect\n",
"\n",
"def new_build_class(*arg, **kw):\n",
" global new_func\n",
" new_func = arg[0]\n",
" \n",
" def f():\n",
" global res, frame\n",
" frame = inspect.currentframe()\n",
" res = new_func()\n",
" return res\n",
" \n",
" tmp = list(arg)\n",
" tmp[0] = f\n",
" arg = tuple(tmp)\n",
" \n",
" res = old__build_class__(*arg, **kw)\n",
" return res\n",
"\n",
"__builtin__.__build_class__, old__build_class__ = new_build_class, __build_class__"
]
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python [default]",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment