Python多重继承函数覆盖和django中的ListView

Jor*_*ata 17 python django listview multiple-inheritance django-generic-views

我创建了一个子类ListView和两个已实现get_context_data函数的自定义mixin的类.我想在子类上覆盖此函数:

from django.views.generic import ListView

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListSortedMixin'
        return kwargs

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListPaginatedMixin'
        return kwargs

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
  def get_context_data(self, **context):
    super(ListSortedMixin,self).get_context_data(**context)
    super(ListPaginatedMixin,self).get_context_data(**context)
    return context
Run Code Online (Sandbox Code Playgroud)

当我执行MyListView它时只打印"ListSortedMixin".出于某种原因,python正在执行ListSortedMixin.get_context_data而不是代替MyListView.get_context_data.为什么?

如果我将继承顺序更改为ListPaginatedMixin, ListSortedMixin, ListView,ListPaginatedMixin.get_context_data则执行.

我该如何覆盖该get_context_data功能?

Dan*_*alm 20

这是一个老问题,但我认为答案是不正确的.您的代码中存在错误.它应该是:

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
    def get_context_data(self, **context):
        super(MyListView,self).get_context_data(**context)
        return context
Run Code Online (Sandbox Code Playgroud)

在其中的顺序get_context_data将被称为如下如在声明中指定的相同顺序MyListView.注意super的参数是,MyListView而不是超类.

更新:

我错过了你的mixins不叫超级.他们应该.是的,即使它们继承自object,因为super调用MRO中的下一个方法,不一定是它所在的类的父类.

from django.views.generic import ListView

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListSortedMixin'
        return super(ListSortedMixin,self).get_context_data(**context)

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListPaginatedMixin'
        return super(ListPaginatedMixin,self).get_context_data(**context)

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
    def get_context_data(self, **context):
        return super(MyListView,self).get_context_data(**context)
Run Code Online (Sandbox Code Playgroud)

对于MyListViewMRO来说:

  1. MyListView
  2. ListSortedMixin
  3. ListPaginatedMixin
  4. 列表显示
  5. 无论ListView上面是什么... n.宾语

逐个调用它们可能有效,但不是如何使用它.

更新2

复制并粘贴示例以证明我的观点.

class Parent(object):
    def get_context_data(self, **kwargs):
        print 'Parent'

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListSortedMixin'
        return super(ListSortedMixin,self).get_context_data(**kwargs)

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListPaginatedMixin'
        return super(ListPaginatedMixin,self).get_context_data(**kwargs)

class MyListView(ListSortedMixin, ListPaginatedMixin, Parent):
    def get_context_data(self, **kwargs):
        return super(MyListView,self).get_context_data(**kwargs)


m = MyListView()
m.get_context_data(l='l')
Run Code Online (Sandbox Code Playgroud)


Mar*_*mro 10

如果你要做的是按固定顺序调用覆盖的方法.使用以下语法:

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
  def get_context_data(self, **context):
    ListSortedMixin.get_context_data(self, **context)
    ListPaginatedMixin.get_context_data(self, **context)
    return context
Run Code Online (Sandbox Code Playgroud)

在这种情况下,超级不起作用.请参阅手册super(type[, object]):

返回将方法调用委托给父类或兄弟类类型的代理对象.这对于访问已在类中重写的继承方法很有用.搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身.

super有两个典型的用例.在具有单继承的类层次结构中,super可用于引用父类而不显式命名它们,从而使代码更易于维护.这种用法与其他编程语言中super的使用密切相关.

第二个用例是在动态执行环境中支持协作多重继承.此用例是Python独有的,在静态编译语言或仅支持单继承的语言中找不到.这使得实现"菱形图"成为可能,其中多个基类实现相同的方法.好的设计要求此方法在每种情况下都具有相同的调用签名(因为调用的顺序是在运行时确定的,因为该顺序适应类层次结构中的更改,并且因为该顺序可以包括在运行时之前未知的兄弟类).

所以super的参数是你想要获得父类或兄弟类代理的类.super(ListSortedMixin,self).get_context_data(**context)不一定会叫get_context_dataListSortedMixin.这取决于您可以使用的方法分辨率顺序(MRO)print MyListView.__mro__

所以super()会打电话给get_context_data父母或兄弟姐妹.执行顺序适应类层次结构中的更改,因为该顺序可以包括运行时之前未知的兄弟类.