I'm trying to understand how super()
works. I understand what it does, but I don't understand the mechanics of what's going on behind the scenes. One thing I don't exactly understand is the difference between:
class b(a):
def __init__(self, name, age):
self.name=name
self.age=age
super(b, self).__init__(name, age)
and:
class b(a):
def __init__(self, name, age):
super(b, self).__init__(name, age)
self.name=name
self.age=age
Maybe there is no difference in these two examples, but I know there are other situations where the placement of super()
matters. For example, this Django method I needed help with the other day, I was instructed to move super()
above the if statement, rather than at the bottom. I would like to know why this matters.
class Mymodel(models.Model):
photo = models.ImageField(upload_to="...", blank=True)
def save(self, *args, **kwargs):
image_resized = kwargs.pop('image_resized',False)
super(Mymodel, self).save(*args, **kwargs)
if self.photo and image_resized:
basewidth = 300
filename = self.get_source_filename()
image = Image.open(filename)
wpercent = (basewidth/float(image.size[0]))
hsize = int((float(image.size[1])*float(wpercent)))
img = image.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
self.photo = img
self.save(image_resized = True)
The difference between your two versions of class b
(if any) depends entirely on what the superclass (a
) does. Let's just take a simpler, sharper example:
class a(object):
def __init__(self):
self.foo = 23
class b1(a):
def __init__(self, name, age):
self.foo = 42
super(b, self).__init__()
class b2(a):
def __init__(self, name, age):
super(b, self).__init__()
self.foo = 42
Class b1
first sets foo
to 42 -- then (in practice) calls a.__init__
, which resets the same attribute to 23. So, self.foo
ends up being worth 23 after b1.__init__
.
Class b2
first (in practice) calls a.__init__
, which sets foo
to 23 -- then, it proceeds to reset the same attribute to 42. So, self.foo
ends up being worth 42 after b2.__init__
.
I find this case simpler and sharper because it boils down to two assignments of different values to the same thing -- so it's very intuitive that the second assignment overrides the effect of the first one. Therefore, calling the superclass's __init__
before the subclass does its own thing means the subclass gets to override some or all of the settings done in the superclass; calling it after, means exactly the reverse.
And exactly the same reasoning applies for initialization operations that are a bit subtler than just plain assignments to self
attributes: it's all about which class, sub or super, gets to tweak or overrule things done by the other (in as much as the two initializations matter at all).
In OOP it's far more common to want the subclass to "override" the superclass, than vice versa; as a consequence, the normal time to call the superclass's __init__
is right at the start of the subclass's -- that's just more idiomatic. When subtler effects are wanted, then it's fine to call the superclass's __init__
later, but in those "slightly anomalous" cases it would usually help a reader of the code to add comments explaining what's being done and why...
super().__init__()
executes the constructor of the class that "this"(or self in py) inherits from. So if there are actions that modifies inherited variables, or variables that need to be used in the constructor of the class that inherits, it must be called before.
Otherwise it does not matter when it is called as long as you don't need it yet. Although it is best practice to always call it in the beginning of a constructor so you always know where it is called(if it is ever needed).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With