在方法的开头或结尾调用 super() 有什么区别?

What is the difference between super() being called at the beginning or end of a method?

我正在尝试了解 super() 的工作原理。我了解它的作用,但我不了解幕后发生的事情的机制。我不太明白的一件事是:

class b(a):
    def __init__(self, name, age):
        self.name=name
        self.age=age
        super(b, self).__init__(name, age)

和:

class b(a):
    def __init__(self, name, age):
        super(b, self).__init__(name, age)
        self.name=name
        self.age=age

也许这两个示例没有区别,但我知道在其他情况下 super() 的位置很重要。例如,前几天我需要帮助的这个 Django 方法,我被指示将 super() 移动到 if 语句上方,而不是底部。我想知道为什么这很重要。

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)

super().__init__() 执行 "this"(或 py 中的 self)继承的 class 的构造函数。所以如果有修改继承变量的动作,或者在继承的class的构造函数中需要用到的变量,必须先调用。 否则,只要您还不需要它,何时调用它都没有关系。虽然最佳做法是始终在构造函数的开头调用它,以便您始终知道它在哪里被调用(如果需要的话)。

class b(如果有)的两个版本之间的区别完全取决于超级class(a)的作用。让我们举一个更简单、更清晰的例子:

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 首先将 foo 设置为 42——然后(实际上)调用 a.__init__,将相同的属性重置为 23。因此,self.foob1.__init__ 之后最终值 23。

Class b2 首先(实际上)调用 a.__init__,它将 foo 设置为 23 —— 然后,它继续将相同的属性重置为 42。因此,self.foob2.__init__ 之后最终值 42。

我发现这种情况更简单、更清晰,因为它归结为对同一事物进行两次不同值的赋值——因此非常直观的是,第二次赋值覆盖了第一次赋值的效果。因此,在 subclass 执行自己的操作之前调用 superclass 的 __init__ 意味着 subclass 会覆盖 superclass 中完成的部分或全部设置class;之后调用它,意思正好相反。

完全相同的推理适用于初始化操作,这些操作比对 self 属性的简单赋值要微妙一些:它是关于 class、sub 或 super 进行调整或否决的由对方完成的事情(就两个初始化而言非常重要)。

在 OOP 中,希望子 class 到 "override" 超级 class 比相反更常见;因此,调用 superclass 的 __init__ 的正常时间恰好在 subclass 的开头——这更符合习惯。当需要更微妙的效果时,稍后调用 superclass 的 __init__ 很好,但在那些 "slightly anomalous" 情况下,它通常会帮助代码的 reader添加评论解释正在做什么以及为什么...