84

Is super() not meant to be used with staticmethods?

When I try something like

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

I get the following error

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'

If I change the staticmethods to classmethods and pass the class instance to super(), things work fine. Am I calling super(type) incorrectly here or is there something I'm missing?

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
Ben J
  • 2,252
  • 4
  • 23
  • 30

4 Answers4

106

The short answer to

Am I calling super(type) incorrectly here or is there something I'm missing?

is: yes, you're calling it incorrectly... AND (indeed, because) there is something you're missing.

But don't feel bad; this is an extremely difficult subject.

The documentation notes that

If the second argument is omitted, the super object returned is unbound.

The use case for unbound super objects is extremely narrow and rare. See these articles by Michele Simionato for his discussion on super():

Also, he argues strongly for removing unbound super from Python 3 here.

I said you were calling it "incorrectly" (though correctness is largely meaningless without context, and a toy example doesn't give much context). Because unbound super is so rare, and possibly just flat-out unjustified, as argued by Simionato, the "correct" way to use super() is to provide the second argument.

In your case, the simplest way to make your example work is

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

If you think it looks funny that way, you're not wrong. But I think what most people are expecting when they see super(X) (or hoping for when they try it in their own code) is what Python gives you if you do super(X, X).

John Y
  • 14,123
  • 2
  • 48
  • 72
  • 10
    Is this any different in Python 3, where `super()` without any arguments is the usual way to call it in a regular method? I had the same problem in Python3 when calling `super().foo()`. – gerrit Sep 22 '16 at 14:24
  • 30
    @gerrit: Python 3's zero-argument `super()` only works in class or instance methods. This is due to the magic that it uses to determine which class it's being defined in. Within static methods (just as in regular, module-level functions), you still need two explicit arguments. (The single-argument form is also still unbound in Python 3.) – John Y Sep 22 '16 at 22:13
  • God bless you and your family – shakedzy May 11 '23 at 08:37
6

When you call a normal method on a object instance, the method receives the object instance as first parameter. It can get the class of the object and its parent class, so it makes sense to call super.

When you call a class method on an object instance or on a class, the method receives the class as first parameter. It can get the parent class, so it makes sense to call super.

But when you call a static method, the method does not receive anything and has no way to know from what object or class it was called. That's the reason why you cannot access super in a static method.

John Y
  • 14,123
  • 2
  • 48
  • 72
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
3

Since Second inherits form First, you can just use First.getlist() instead of passing in two arguments in super(i.e. 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)
Peter
  • 202
  • 2
  • 5
  • 10
    However, this can get screwed up if you later change the ancestry. For example, if an intermediate class `OnePointFive` is added in the inheritance tree in between `First` and `Second`, `Second` will skip a level when calling what used to be its super. – RawwrBag May 01 '20 at 23:31
-1

You may wonder if the python documentation is wrong when claiming in paragraph 2 in 3.11.1 Documentation » The Python Language Reference » 3. Data model 3.3.1. Basic customization :

"Typical implementations create a new instance of the class by invoking the superclass’s new() method using super().new(cls[, ...]) with appropriate arguments and then modifying the newly created instance as necessary before returning it."

The dubious part is "using super().new(cls[, ...])"...?

FooFee
  • 1