说真的:您真的不想这样做。
但是,这对于Python的高级用户了解这一点很有用,因此我将对其进行解释。
单元格和freevar是创建闭包时分配的值。例如,
def f(): a = 1 def func(): print(a) return func
f返回基于的闭包
func,并存储对的引用
a。该引用存储在一个单元中(实际上存储在一个freevar中,但这取决于实现)。您可以检查以下内容:
myfunc = f()# ('a',)print(myfunc.__pre__.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 typesclass 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 pre 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_pre, 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_pre = MakeCodeObjectWithClass(__init__.__pre__)old_closure = __init__.__closure__ or ()C.__init__ = types.FunctionType(new_pre, globals(), __init__.__name__, __init__.__defaults__, old_closure + (C.dummy.__closure__[0],))if __name__ == '__main__': c = C()


