18

Here's some code in a django tutorial that I'm going through. I've never come across the super function in python before and the way it's used here is different from the examples I've seen online. I.e., usually when you use super, don't you have multiple classes? It's in the last line: super(Snippet, self).save(force_insert, force_update) Could you explain exactly what's going on there and what would be an alternative way to write that. It just seems like the save method is calling itself here?

class Snippet(models.Model):
    title = models.CharField(max_length=255)
    language = models.ForeignKey(Language)
    author = models.ForeignKey(User)
    description = models.TextField()
    description_html = models.TextField(editable=False)
    code = models.TextField()
    highlighted_code = models.TextField(editable=False)
    tags = TagField()
    pub_date = models.DateTimeField(editable=False)
    updated_date = models.DateTimeField(editable=False)

    class Meta:
        ordering = ['-pub_date']

    def __unicode__(self):
        return self.title

    def save(self, force_insert=False, force_update=False):
        if not self.id:
            self.pub_date = datetime.datetime.now()
        self.updated_date = datetime.datetime.now()
        self.description_html = markdown(self.description)
        self.highlighted_code = self.highlight()
        super(Snippet, self).save(force_insert, force_update)

2 Answers2

41

super(Snippet, self) causes Python to look in the MRO of the class of self (i.e. self.__class__.mro() for the next class listed after Snippet. It returns a super object which acts as a proxy for that class. That is, calling a method on the super object acts like calling that method on the class.

super(Snippet, self).save(...) calls that class's save method, with self bound to the first argument.

So super(Snippet, self).save(...) will not call Snippet's save method; it will call some other class's save method. It is tempting to think this "other class" is the "parent class" or "superclass" of Snippet, that is, models.Model, but that may not be true and it is absolutely wrong to apprehend super this way. Which class super(Snippet, self) ultimately represents depends on self and in particular its class's MRO.

A very good description of the MRO and super (complete with pictures!) can be found here.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
4

I won't explain again what unutbu explained on super classes, however you obtain the same effect with the following code :

models.Model.save(self, force_insert, force_update)

This is NOT a better way to write it since, if you come to change the class inheritance by adding an intermediate class between Model and Snippet you would also have to change this line (which you would most likely forget). Anyway it's a good thing to know.

I can also add that the super instruction only works if the class you inherit from extends from object, otherwise you get an exception.

JC Plessis
  • 683
  • 3
  • 7
  • 2
    It's not only if Snippet's ancestors are changed; if there is a certain form of multiple inheritance in a child class of Snippet, the result could be different to the correct `super(Snippet, self)`. – Chris Morgan Aug 22 '11 at 10:55