3

I'd like to ask about

sup = super(self, self)

Python Cookbook 3rd by David Beazley & Brian K. Jones has a number of such examples. This is the abbreviated excerpt of code of one from the book:

class MatchSignaturesMeta(type):
    def __init__(self, clsname, bases, clsdict):
        super().__init__(clsname, bases, clsdict)
        sup = super(self, self)  
        for name, value in clsdict.items():
        # ...
            prev_dfn = getattr(sup, name, None)
        # ...

class Root(metaclass=MatchSignaturesMeta):
    pass
class A(Root):
    def foo(self, x, y):
        pass
    # ...

through experiment I know that the second super argument is mandatory. sup is printed as:

<super: <class 'Root'>, <Root object>>

In the documentation super they say

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

"Bound/unbound method" (a function with its 1st parameter bound to the class instance) is familiar. What is the "bound object" ?

In the example the Root class is being created. I see no explicit Root object creation. I'd like to ask where did Root object (from the sup printable representation above) come from?

Using Python 3.5.3 on Debian GNU/Linux 9.11 (stretch)

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343

1 Answers1

0

Unbound super object is a descriptor - https://docs.python.org/3/glossary.html#term-descriptor . It means that it has special behaviour when it is accessed as an object property.

It has no methods definition inside itself. However it can create bound super objects through descriptor's API.

Consider we have three following classes and unbound super object:

class A(object):
    def method(self):
        return 'a'

class B(A):
    def method(self):
        return 'b'

sup = super(B)

If you try to pick methods or properties from you will fail:

sup.method
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-de4aeea2d9e8> in <module>
      1 # If you try to get any method of A, it won't work
----> 2 sup.method

AttributeError: 'super' object has no attribute 'method'

But if you try to assign it to a different property, it will use descriptor's __get__ method, which works this:

def __get__(self, instance, owner=None):
    return super(self.__thisclass__, instance)

where __thisclass__ - is the single argument to super constructor (in our case - it is B).

So if we try to access the property through the instance we will be able to reach superclass's method:

class C(B):
    sup = super(B)

# same as super(B, self).method()
C().sup.method() # -> 'a'

But keep in mind, that you're unable to get unbound superclass method via C.sup.method. Because it is equivalent to super(B, None) which is in turn equivalent to super(B).