简体   繁体   English

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

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

I'm trying to understand how super() works. 我试图了解super()工作原理。 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. 也许这两个例子没有区别,但我知道还有其他情况下super()的位置很重要。 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. 例如,这个Django方法我前几天需要帮助,我被指示将super()移到if语句之上,而不是在底部。 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. 你的两个版本的b类(如果有的话)之间的区别完全取决于超类( a )的作用。 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__ . b1首先将foo设置为42 - 然后(实际上)调用a.__init__ ,它将相同的属性重置为23.因此, self.foob1.__init__之后最终值23。

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__ . b2首先(在实践中)调用a.__init__ ,它将foo设置为23 - 然后,它继续将相同的属性重置为42.因此, self.foob2.__init__之后最终值为42。

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; 因此,在子类执行自己的事情之前调用超类的__init__意味着子类可以覆盖超类中完成的部分或全部设置; 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). 完全相同的推理适用于初始化操作,这些操作比self属性的简单赋值更微妙:它是关于哪个类,子或超级调整或否决另一个完成的事情(在两个初始化中完成)完全没问题)。

In OOP it's far more common to want the subclass to "override" the superclass, than vice versa; 在OOP中,通常希望子类“覆盖”超类,反之亦然; 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. 因此,调用超类的__init__的正常时间就在子类的开头 - 这只是更惯用的。 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... 当需要更微妙的效果时,可以稍后调用超类的__init__ ,但在那些“稍微异常”的情况下,它通常会帮助读者的代码添加注释来解释正在做什么以及为什么......

super().__init__() executes the constructor of the class that "this"(or self in py) inherits from. super().__init__()执行“this”(或py中的self)继承自的类的构造函数。 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). 虽然最好总是在构造函数的开头调用它,这样你总能知道它的调用位置(如果需要的话)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM