如何在Python 2.6+中使用super(...)时避免样板代码?

5
有没有好的方法(适用于实际项目)来减少类似这样的样板代码?
class B(A):
    def qqq(self): # 1 unwanted token "self"
        super(B, self).qqq() # 7 unwanted tokens plus 2 duplications ("B", "qqq")
        do_something()

我希望它看起来更像这样:

我希望它的外观更接近这个样子:

class B(A):
    def qqq:
        super
        do_something()

或者(更现实的情况)
class B(A):
    @autosuper_before
    def qqq(self):
        do_something()

在Python 2.6+中是否可能不需要明显的黑客手段来实现呢?

@link Python 2.x中没有参数的super()


4
与其与 self 参数作斗争,直接明示更佳。 特殊情况并不特别到足以打破规则,等等。 另外,有多少次您会覆盖一个没有参数且在调用下一个实现之前不执行任何操作的方法? - user395760
“overt hacks” 是什么意思? - BrenBarn
@BrenBarn,“Overt Hacks”在这里的意思是“代码变得更简单,但代价是巨大的减速、丑陋的回溯或其他不愉快的事情”。 - Vi.
1个回答

4

简而言之

正如原帖所说“在Python 2.6+中是否可能没有明显的黑客行为?”,答案是:不可能

详细说明

您可以创建一个简单的装饰器,将调用下一个具有此方法的父级。问题是,您将无法控制要传递的参数。

编辑: 对于已经使用autosuper的子类,这将无效,因为它会选择错误的类并导致无限循环。

def autosuper(fn):
    def f(self, *args, **kw):
        cl = super(type(self), self)
        getattr(cl, fn.__name__)(*args, **kw)
        return fn(self, *args, **kw)
    return f

如何实现?Python 3.x确实有一个不需要参数的super函数!

但遗憾的是,Python 3.x的super既是一个类,又是一个关键字。因为其名称的存在将更改当前环境,以揭示一个名为__class__的变量,这就是您需要使用的正确类!

如果您检查在类中声明的函数内部的帧,那么就没有__class__变量,并且帧的f_code属性的co_freevars属性为空。当您编写名称super(无需调用它)时,__class__字符串将出现在co_freevars中,表示它来自另一个闭包。此外,如果您尝试访问__class__变量而不使用super,则会出现LOAD_DEFER字节码,出于同样的原因,而不是像对每个未定义的名称一样正常使用LOAD_GLOBAL

这太疯狂了,你不能只是做hyper = super并调用这个新的hyper变量而不带参数(这正是与super完全相同的对象)。
由于我无法与Python解释器内部的黑魔法竞争,而且因为autosuper装饰器没有在类中声明(即使在Python 2.x中可能是可能的,它也永远无法访问__class__变量),所以我不会尝试编写新的装饰器,并将这个答案留在这里,作为其他想要这样做的人的警告。
可能可以通过一些技巧找到正确的类来使用,但我不会深入挖掘。需要考虑的事情:
  • 当装饰器被应用时,类尚不存在,因此应在调用装饰函数时执行。
  • 被装饰的函数尚未成为一个未绑定方法(在Py3k中已经被删除),因此您无法检查im_class属性。
  • 该帧似乎没有保留任何有关用于进行此调用的类的信息(除非__class__变量确实存在并且可以获取对其的引用)
  • 此答案由OP提供也相当错误,因为它做出了许多错误的假设,并且在装饰函数方面存在问题。

我总是忘记一遍又一遍地添加“self”。(当我更改类的名称或方法的名称时,还会忘记更改参数或“super”在许多方法中)。 - Vi.
它应该运行得相当快吗?它看起来有点像Java的反射,据说很慢。是否可以将“反射”从“f”移动到“autosuper”,让“f”调用已经准备好的东西,以保持其轻量级?(实际上,我想要类似于Lisp宏的东西,它会自动添加那个“super(...)”行) - Vi.
@Vi。Java反射使用类似的语法,但与装饰器非常不同。它只会添加一个额外的函数调用。顺便说一下,我已经更改了代码,使用super函数而不是编写自己的函数。 - JBernardo
如果您添加了一个额外的继承级别(即,一个也使用autosuper的class E(D)),这种方法将无法正常工作。在这种情况下,type(self)将被计算为E,因此D.foo将尝试调用自身并导致无限递归。 - BrenBarn
问题似乎足够严格,以防止真正使用这个装饰器。如何访问应用装饰器的类的类型,以便使用它而不是type(self)? - Vi.
@Vi。我正在检查Python 3如何没有参数地使用'super',它使用了很多黑魔法和隐藏变量“__class__”,仅在函数编写在类内部时才可用。因此,在Python 2.x上无法重现此行为(并且装饰器是在类外声明的)。您可以制作一个装饰器并传递正确的类名,但那将是一个“不需要的标记”... - JBernardo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接