在Python 3中,可以使用super()
而不是super(MyClass, self)
,但这仅适用于在类中定义的方法。如Michele Simionato's article中所述,以下示例不起作用:
def __init__(self):
print('calling __init__')
super().__init__()
class C(object):
__init__ = __init__
if __name__ == '__main__':
c = C()
失败是因为super()
查找了__class__
cell,在这种情况下未定义。
是否可以在定义功能后手动设置此单元格,还是不可能?
不幸的是,我不明白单元格在这种情况下是如何工作的(没有找到很多文档)。我希望像
这样的东西__init__.__class_cell_thingy__ = C
当然我只会在类分配明确/唯一的情况下使用它(在我的情况下,将类添加到类的整个过程是自动化的,所以添加这样的行很简单)。
答案 0 :(得分:19)
说真的:你真的不想这样做。
但是,对于Python的高级用户来说理解这一点很有用,所以我会解释它。
Cells和freevars是创建闭包时分配的值。例如,
def f():
a = 1
def func():
print(a)
return func
f
返回基于func
的闭包,存储对a
的引用。该引用存储在一个单元格中(实际上存在于freevar中,但哪一个取决于实现)。你可以检查一下:
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 - 所以我们需要添加一个。{1}}函数。这意味着我们还必须创建一个新的代码对象。
以下代码执行此操作。为了演示目的,我添加了一个基类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()
答案 1 :(得分:2)
您可以使用该功能的字典。
def f(self):
super(f.owner_cls, self).f()
print("B")
def add_to_class(cls, member, name=None):
if hasattr(member, 'owner_cls'):
raise ValueError("%r already added to class %r" % (member, member.owner_cls))
member.owner_cls = cls
if name is None:
name = member.__name__
setattr(cls, name, member)
class A:
def f(self):
print("A")
class B(A):
pass
add_to_class(B, f)
B().f()
如果您不想硬编码函数内成员名称的名称,您甚至可以添加另一个属性member_name
。
答案 2 :(得分:1)
也许吧,不过你呢?在这两种情况下,您都需要以某种方式明确它是哪个类,因为隐式方法不起作用。也许你可以以某种方式明确地设置单元格,但没有理由这样做。只需明确传递参数。
def __init__(self):
print('calling __init__')
super(self.__class__, self).__init__()
class C(object):
__init__ = __init__
if __name__ == '__main__':
c = C()
(最好直接传入实际的类,如下:
def __init__(self):
print('calling __init__')
super(C, self).__init__()
class C(object):
__init__ = __init__
if __name__ == '__main__':
c = C()
但如果可以的话,你可以直接将__init__
放在C
上,所以假设你不能。{/ p>