说真的:你真的不想这样做。
但是,对于 Python 的高级用户来说理解这一点很有用,所以我将对其进行解释。
单元格和自由变量是创建闭包时分配的值。例如,
def f():
a = 1
def func():
print(a)
return func
f
返回一个基于 的闭包func
,存储对 的引用a
。该引用存储在一个单元格中(实际上是在一个自由变量中,但哪个取决于实现)。你可以检查这个:
myfunc = f()
# ('a',)
print(myfunc.__code__.co_freevars)
# (<cell at 0xb7abce84: int object at 0x82b1de0>,)
print(myfunc.__closure__)
(“cells”和“freevars”非常相似。Freevars 有名称,其中单元格有索引。它们都存储在 中func.__closure__
,单元格首先出现。我们只关心freevars
这里,因为这就是__class__
它。)
一旦你理解了这一点,你就可以看到 super() 是如何工作的。任何包含调用的函数super
实际上都是一个闭包,带有一个名为的 freevar __class__
(如果您引用__class__
自己,也会添加它):
class foo:
def bar(self):
print(__class__)
(警告:这是事情变得邪恶的地方。)
这些单元格在 中可见func.__closure__
,但它是只读的;你不能改变它。更改它的唯一方法是创建一个新函数,该函数由types.FunctionType
构造函数完成。但是,您的__init__
函数根本没有__class__
freevar——所以我们需要添加一个。这意味着我们还必须创建一个新的代码对象。
下面的代码就是这样做的。我添加了一个基类B
用于演示目的。这段代码做了一些假设,例如。还__init__
没有一个名为 的自由变量__class__
。
这里还有另一个技巧:似乎没有单元格类型的构造函数。为了解决这个问题,C.dummy
创建了一个虚拟函数,其中包含我们需要的单元格变量。
import types
class B(object):
def __init__(self):
print("base")
class C(B):
def dummy(self): __class__
def __init__(self):
print('calling __init__')
super().__init__()
def MakeCodeObjectWithClass(c):
"""
Return a copy of the code object c, with __class__ added to the end
of co_freevars.
"""
return types.CodeType(c.co_argcount, c.co_kwonlyargcount, c.co_nlocals,
c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)
new_code = MakeCodeObjectWithClass(__init__.__code__)
old_closure = __init__.__closure__ or ()
C.__init__ = types.FunctionType(new_code, globals(), __init__.__name__,
__init__.__defaults__, old_closure + (C.dummy.__closure__[0],))
if __name__ == '__main__':
c = C()