super()和@staticmethod的互动

87

super()不能与staticmethod一起使用吗?

当我尝试像这样做时

class First(object):
  @staticmethod
  def getlist():
    return ['first']

class Second(First):
  @staticmethod
  def getlist():
    l = super(Second).getlist()
    l.append('second')
    return l

a = Second.getlist()
print a

我收到了以下错误信息

Traceback (most recent call last):
  File "asdf.py", line 13, in <module>
    a = Second.getlist()
  File "asdf.py", line 9, in getlist
    l = super(Second).getlist()
AttributeError: 'super' object has no attribute 'getlist'

如果我将静态方法更改为类方法,并将类实例传递给super(),那么事情就会很顺利。我在这里调用super(type)有问题吗,还是我漏掉了什么?


这些应该是类方法 - Neil G
4个回答

109

简短的回答是:是的,你调用它的方式不正确...... 而且(事实上,因为)你忽略了一些东西。

但别难过;这是一个非常困难的主题。

文档指出:

如果省略第二个参数,则返回的 super 对象是未绑定的。

未绑定 super 对象的使用情况非常狭窄和罕见。请参阅 Michele Simionato 的这些文章,了解他对 super() 的讨论:

此外,他强烈主张在 Python 3 中删除未绑定的 super,可以在这里看到。

我说你的调用方式是“不正确”的(尽管正确性在没有上下文的情况下意义不大,而玩具示例也没有太多上下文)。由于未绑定的 super 如此罕见,并且可能完全没有道理,就像 Simionato 所断言的那样,“正确”使用 super() 的方法是提供第二个参数。

在你的情况下,使你的示例工作的最简单方法是:

class First(object):
  @staticmethod
  def getlist():
    return ['first']

class Second(First):
  @staticmethod
  def getlist():
    l = super(Second, Second).getlist()  # note the 2nd argument
    l.append('second')
    return l

a = Second.getlist()
print a

如果你觉得它看起来很奇怪,那么你没有错。但是我认为当大多数人看到super(X)时(或者在他们自己的代码中尝试时所希望的),他们期望的是Python提供的super(X, X)的效果。


10
在Python 3中,使用super()而不带任何参数是在常规方法中调用它的常用方式,这与Python 2有所不同。当调用super().foo()时,我在Python 3中遇到了相同的问题。 - gerrit
31
Python 3的零参数super()只能在类或实例方法中使用。这是由于super()用于确定所定义类的魔法特性。在静态方法中(就像普通的模块级函数一样),你仍然需要两个显式参数。(Python 3中的单参数形式也仍然未被绑定。) - John Y
把你和你的家人保佑。 - shakedzy

6
当您在对象实例上调用普通方法时,该方法将接收对象实例作为第一个参数。它可以获取对象的类和其父类,因此调用super是有意义的。
当您在对象实例或类上调用类方法时,该方法将接收类作为第一个参数。它可以获取父类,因此调用super是有意义的。
但是,当您调用静态方法时,该方法不会接收任何内容,并且没有办法知道从哪个对象或类中调用它。这就是为什么您不能在静态方法中访问super的原因。

3

由于Second继承于First,因此您可以直接使用First.getlist()而不必在super中传递两个参数(即super(Second, Second))。

class First(object):
   @staticmethod
   def getlist():
     return ['first']

class Second(First):
  @staticmethod
  def getlist():
    # l = super(Second, Second).getlist()
    l = First.getlist()
    l.append('second')
    return l

a = Second.getlist()
print (a)

12
然而,如果后来更改了祖先关系,这可能会出现问题。例如,如果在FirstSecond之间的继承树中添加一个中间类OnePointFive,那么当调用原本是其超类的内容时,Second将跳过一个级别。 - RawwrBag

-1
您可能会想知道,Python文档在3.11.1文档»Python语言参考»3.数据模型3.3.1.基本自定义的第二段中声称的是否有误:
“典型的实现通过使用super().new(cls[, ...])调用超类的new()方法并使用适当的参数创建一个新的类实例,然后根据需要修改新创建的实例,最后返回它。”
可疑的部分是"using super().new(cls[, ...])"吗?

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