super() quiz

Who am I?

Aleksey Rembish

Siberian

Python Enthusiast

Lead Python/DevOps programmer at

super()?

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

Tier Zero

class Language:
    def hello(self, name):
        return "Hello from {0}".format(name)


class Python27(Language):
    def hello(self):
        return super(Python27, self) \
            .hello("Python 2.7")


print Python27().hello()
class Language:
    def hello(self, name):
        return "Hello from {0}".format(name)


class Python27(Language):
    def hello(self):
        return super(Python27, self) \
            .hello("Python 2.7")


print Python27().hello()
TypeError: super() argument 1
must be type, not classobj

class Language:
    def hello(self, name):
        return "Hello from {0}".format(name)


class Python35(Language):
    def hello(self):
        return super(Python35, self) \
            .hello("Python 3.5")


print(Python35().hello())
class Language:
    def hello(self, name):
        return "Hello from {0}".format(name)


class Python35(Language):
    def hello(self):
        return super(Python35, self) \
            .hello("Python 3.5")


print(Python35().hello())
Hello from Python 3.5

super() works only with new-style classes in py2k

Tier One

class Colour(object):  # Python 2.7
    def __init__(self, rgb):
        self.rgb = rgb

    def describe(self):
        return "#{0}".format(self.rgb)

class Blue(Colour):
    def __init__(self):
        super().__init__("0000FF")

print Blue().describe()
class Colour(object):  # Python 2.7
    def __init__(self, rgb):
        self.rgb = rgb

    def describe(self):
        return "#{0}".format(self.rgb)

class Blue(Colour):
    def __init__(self):
        super().__init__("0000FF")

print Blue().describe()
TypeError: super() takes at least 1 argument (0 given)

class Colour(object):  # Python 3.5
    def __init__(self, rgb):
        self.rgb = rgb

    def describe(self):
        return "#{0}".format(self.rgb)

class Yellow(Colour):
    def __init__(self):
        super().__init__("FFFF00")

print(Yellow().describe())
class Colour(object):  # Python 3.5
    def __init__(self, rgb):
        self.rgb = rgb

    def describe(self):
        return "#{0}".format(self.rgb)

class Yellow(Colour):
    def __init__(self):
        super().__init__("FFFF00")

print(Yellow().describe())
#FFFF00

You can use tiny form of super() in py3k

super().method() == super(SubClass, self).method()

Tier Two

class Czechia(object):  # Both Pythons
    def whereami(self):
        print("I'm in Czechia")

Czechia().whereami()
class Czechia(object):  # Both Pythons
    def whereami(self):
        print("I'm in Czechia")

Czechia().whereami()
I'm in Czechia
class Czechia(object):  # Both Pythons
    def whereami(self):
        print("I'm in Czechia")

class Slovakia(object):
    def whereami(self):
        print("I'm in Slovakia")
        super(Slovakia, self).whereami()

# Dash war begins
class Czechoslovakia(Czechia, Slovakia):
    def whereami(self):
        super(Czechoslovakia, self).whereami()
        print("I'm in Czechoslovak Republic")

Czechoslovakia().whereami()
class Czechia(object):  # Both Pythons
    def whereami(self):
        print("I'm in Czechia")

class Slovakia(object):
    def whereami(self):
        print("I'm in Slovakia")
        super(Slovakia, self).whereami()

# Dash war begins
class Czechoslovakia(Czechia, Slovakia):
    def whereami(self):
        super(Czechoslovakia, self).whereami()
        print("I'm in Czechoslovak Republic")

Czechoslovakia().whereami()
I'm in Czechia
I'm in Czechoslovak Republic

class Czechia(object):  # Both Pythons
    def whereami(self):
        print("I'm in Czechia")

class Slovakia(object):
    def whereami(self):
        print("I'm in Slovakia")
        super(Slovakia, self).whereami()

# Dash war continues (I can't use dash in a class name)
class Czecho_SlovakRepublic(Slovakia, Czechia):
    def whereami(self):
        super(Czecho_SlovakRepublic, self).whereami()
        print("I'm in Czecho-Slovak Republic")

Czecho_SlovakRepublic().whereami()
class Czechia(object):  # Both Pythons
    def whereami(self):
        print("I'm in Czechia")

class Slovakia(object):
    def whereami(self):
        print("I'm in Slovakia")
        super(Slovakia, self).whereami()

# Dash war continues (I can't use dash in a class name)
class Czecho_SlovakRepublic(Slovakia, Czechia):
    def whereami(self):
        super(Czecho_SlovakRepublic, self).whereami()
        print("I'm in Czecho-Slovak Republic")

Czecho_SlovakRepublic().whereami()
I'm in Slovakia
I'm in Czechia
I'm in Czecho-Slovak Republic
Czechoslovakia
  • <class 'Czechoslovakia'>
  • <class 'Czechia'>
  • <class 'Slovakia'>
  • <class 'object'>
Czecho_SlovakRepublic

MRO differences

  • <class 'Czecho_SlovakRepublic'>
  • <class 'Slovakia'>
  • <class 'Czechia'>
  • <class 'object'>
super() calls

super() returns a proxy object that delegates method calls to a parent or sibling class of type

Tier Three

class Reptile(object):  # Both Pythons
    def describe(self):
        return "Reptile"

class Snake(Reptile):
    def describe(self):
        return "Snake"

class Python(Snake):
    def describe(self):
        return "Python"

print(super(Python, Python()).describe())
class Reptile(object):  # Both Pythons
    def describe(self):
        return "Reptile"

class Snake(Reptile):
    def describe(self):
        return "Snake"

class Python(Snake):
    def describe(self):
        return "Python"

print(super(Python, Python()).describe())
Snake
class Reptile(object):  # Both Pythons
    def describe(self):
        return "Reptile"

class Snake(Reptile):
    def describe(self):
        return "Snake"

class Python(Snake):
    def describe(self):
        return "Python"

print(super(Snake, Snake).describe(Python()))
class Reptile(object):  # Both Pythons
    def describe(self):
        return "Reptile"

class Snake(Reptile):
    def describe(self):
        return "Snake"

class Python(Snake):
    def describe(self):
        return "Python"

print(super(Snake, Snake).describe(Python()))
Reptile

You can use super() out of your class context

Using class (instead of instance) as a second parameter of super() produces unbounded method

Tier Four

class Meetup(object):  # Both Pythons
    name = "Meetup"

class PythonMeetup(Meetup):
    name = "Python Meetup"

class PyVo(PythonMeetup):
    name = "PyVo"
    type = super(PythonMeetup)

print(Meetup.name)
print(PythonMeetup().name)
print(PyVo().name)
class Meetup(object):  # Both Pythons
    name = "Meetup"

class PythonMeetup(Meetup):
    name = "Python Meetup"

class PyVo(PythonMeetup):
    name = "PyVo"
    type = super(PythonMeetup)

print(Meetup.name)
print(PythonMeetup().name)
print(PyVo().name)
Meetup
Python Meetup
PyVo
class Meetup(object):  # Both Pythons
    name = "Meetup"

class PythonMeetup(Meetup):
    name = "Python Meetup"

class PyVo(PythonMeetup):
    name = "PyVo"
    type = super(PythonMeetup)

print(PyVo().type.name)
class Meetup(object):  # Both Pythons
    name = "Meetup"

class PythonMeetup(Meetup):
    name = "Python Meetup"

class PyVo(PythonMeetup):
    name = "PyVo"
    type = super(PythonMeetup)

print(PyVo().type.name)
Meetup
something = super(PythonMeetup)

print(type(something))  # => <type 'super'>
# `something` is unbounded super object

print(something.name)  # => ?
something = super(PythonMeetup)

print(something.name)
# AttributeError: 'super' object has no
#   attribute 'name'

print(dir(something))
# [
#   '__get__', '__getattribute__', 
#   '__init__', '__new__', ...
# ]

sup = PyVo().type
print(type(sup))  # => <type 'super'>
pyvo = PyVo()
pyvo.type.name

# == super(PythonMeetup).__get__(pyvo, PyVo).name
# == super(PythonMeetup, pyvo).name
# == "Meetup"
class Meetup(object):  # Both Pythons
    name = "Meetup"

class PythonMeetup(Meetup):
    name = "Python Meetup"

class PyVo(PythonMeetup):
    name = "PyVo"
    type = super(PythonMeetup)

print(PyVo.type.name)
class Meetup(object):  # Both Pythons
    name = "Meetup"

class PythonMeetup(Meetup):
    name = "Python Meetup"

class PyVo(PythonMeetup):
    name = "PyVo"
    type = super(PythonMeetup)

print(PyVo.type.name)
AttributeError: 'super' object has no attribute 'name'

Tier Five

class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

Human().mynameis()
class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

Human().mynameis()
Human said: I'm Human
class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

class Pepa(Human):
    @classmethod
    def mynameis(cls):
        print("Pepa said: I'm {0}".format(cls.__name__))
        cls.__super.mynameis()

Pepa._Pepa__super = super(Pepa)

Pepa().mynameis()

Edit from 2022: There is a mistake in this code. It will produce an AttributeError for Pepa and Josef (next slides). Check this snippet to observe working, but wacky behavior of super().

Pepa._Pepa__super?!
class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

class Pepa(Human):
    @classmethod
    def mynameis(cls):
        print("Pepa said: I'm {0}".format(cls.__name__))
        cls.__super.mynameis()

Pepa._Pepa__super = super(Pepa)

Pepa().mynameis()
Pepa said: I'm Pepa
class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

class Pepa(Human):
    @classmethod
    def mynameis(cls):
        print("Pepa said: I'm {0}".format(cls.__name__))
        cls.__super.mynameis()

Pepa._Pepa__super = super(Pepa)

Pepa().mynameis()
== super(Pepa, self).mynameis()
class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

class Pepa(Human):
    @classmethod
    def mynameis(cls):
        print("Pepa said: I'm {0}".format(cls.__name__))
        cls.__super.mynameis()

Pepa._Pepa__super = super(Pepa)

class Josef(Pepa):
    pass

Josef._Josef__super = super(Josef)

Josef().mynameis()
class Human(object):  # Both Pythons
    @classmethod
    def mynameis(cls):
        print("Human said: I'm {0}".format(cls.__name__))

class Pepa(Human):
    @classmethod
    def mynameis(cls):
        print("Pepa said: I'm {0}".format(cls.__name__))
        cls.__super.mynameis()

Pepa._Pepa__super = super(Pepa)

class Josef(Pepa):
    pass

Josef._Josef__super = super(Josef)

Josef().mynameis()
AttributeError: 'super' object has no attribute 'mynameis'

You can use unbounded super objects as private attributes, but... please don't do it

Tier Guido

Thanks for proposing this
I've been scratching my head wondering what the use of unbound
super() would be. :-) I'm fine with killing it.
Perhaps someone can do a bit of research to try and find out if there are any real-life uses (apart from various auto-super clones)?

--- Guido van Rossum

Where to go?

We are hiring!

Python 3.5, async, Tornado, Flask, Docker, Kubernetes, Prometheus, GitLab CI, ...

Made with Slides.com