5

实际上我们知道super用于查找“父类”并返回其对象,例如/使用self.__class__.__mro__

我感到困惑的是何时准确使用它?

假设我们有一个示例模型代码如下

版本_1

class Example(models.Model):
    name = models.CharField()
    age  = models.IntegerField()

    def save(self, **args, **kwargs):
        obj = super(Example, self).save(self, **args, **kwargs)
        obj.name = "name changed"
        obj.age = "age changed"
        return obj

版本_2

class Example(models.Model):
    name = models.CharField()
    age  = models.IntegerField()

    def save(self, **args, **kwargs):
        self.name = "name changed"
        self.age = "age changed"
        obj = super(Example, self).save(self, **args, **kwargs)
        return obj

所以我们可以在上面观察到

version_1中,我super首先调用并修改了字段并返回了 obj

version_2中,我修改了字段,然后调用 super 并返回 obj

那么在修改字段之前和之后调用 super 会发生什么?

最后我想知道/确认的是

  • 在 django 表单/模型中使用 super 的位置/原因。
  • 在 django/python 中使用它们的确切概念是什么(如果我理解错了)。
4

3 回答 3

19

Example的类是Model. 这意味着,它Example继承了所有的功能Model

请看以下内容:

class Example():
    pass

example = Example()
#let's try to save it
example.save()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Example instance has no attribute 'save'

现在有了继承。

class Parent():
    def save(*args, **kwargs):
        print "saving now"

class Example(Parent):
    pass

example = Example()
#since Example has no save method, it inherits the Parent's save method.
example.save()
"saving now"

如果您在 Example 类中覆盖 save() 方法,则不会调用 Parent 的 save 方法。

   class Example(Parent):
        def save(self, *args, **kwargs):
            print "i know how to save on my own now"

   example = Example()
   example.save()
   "i know how to save on my own now"

如果您选择调用 super,您将调用 Parent 的 save 函数以及您自己的 save() 实现。

   class Example(Parent):
         def save(self, *args, **kwargs):
              super(Example, self).save(*args, **kwargs)
              print "i know how to save on my own now"

   example = Example()
   example.save()
   "saving now" #from parent
   "i know how to save on my own" #from example

这同样适用于您继承的所有 djangos 类。事实上,实现更复杂。您可以在github上查看模型定义。

如果您感到激动,可以通过本次演讲深入了解 django ORM

于 2013-10-05T12:49:48.710 回答
5

我相信这个问题不是 Django 特有的,因此我将尝试以通用的方式解释它。

super 的实用性在于您不需要指定要调用哪个基类(这也可能是一个缺点,因为 mro 定义了调用什么基类)。

我使用 super 来创建 mixin(关于 SO 有一个很好的答案,描述了什么是 mixin)。一个使用超级的例子:

class LemonMixin(object):
    def tastes_like(self):
        return super(LemonMixin, self).tastes_like() + ' and lemon'

class Cola(object):
    def tastes_like(self):
        return 'sugar'

class ColaLemon(LemonMixin, Cola):
    pass

drink = ColaLemon()
drink.tastes_like()  # returns 'sugar and lemon'

mixin 与 aplied 类无关,因此它可以使用 super 来使用 mro 调用基类。

何时调用 super 完全取决于您。例如,如果您想检查安全性,则在安全检查后调用 super。如果您想在某事完成后触发事件,您可能需要在触发事件之前调用 super。;-)

于 2013-10-05T12:49:17.573 回答
3

你打电话super

  • 首先,如果父母的方法填充了您在治疗中需要的属性
  • 最后,如果您更改某些属性的值并希望将父级的方法处理应用于这些新值

总之,当您想更改父方法的实现时:

  • 转到父级的方法实现。检查做了什么。您的 IDE 可能会简化检索父实现的工作,否则请转到您的 Django 安装目录,然后自行/lib/python/site-packages/django查找实现。
  • 根据您的需要(=使用父方法生成的属性或更改父方法使用的属性的值)在您的自定义代码之前或之后使用 super。
于 2013-10-05T12:42:10.277 回答