django中的Python多重继承函数覆盖和ListView
Posted
技术标签:
【中文标题】django中的Python多重继承函数覆盖和ListView【英文标题】:Python multiple inheritance function overriding and ListView in django 【发布时间】:2012-04-13 22:03:33 【问题描述】:我创建了一个继承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
当我执行MyListView
时,它只打印"ListSortedMixin"
。出于某种原因,python 正在执行ListSortedMixin.get_context_data
代替MyListView.get_context_data
。为什么?
如果我将继承顺序更改为ListPaginatedMixin, ListSortedMixin, ListView
,则会执行ListPaginatedMixin.get_context_data
。
如何覆盖get_context_data
函数?
【问题讨论】:
【参考方案1】:这是一个老问题,但我认为答案不正确。您的代码中有错误。它应该是:
class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
def get_context_data(self, **context):
super(MyListView,self).get_context_data(**context)
return context
get_context_data
的调用顺序与MyListView
声明中指定的顺序相同。注意 super 的参数是 MyListView
而不是超类。
更新:
我错过了你的 mixin 不调用 super。他们应该。是的,即使它们继承自 object,因为 super 调用 MRO 中的 next 方法,不一定是它所在类的父类。
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)
对于MyListView
,MRO 是:
-
我的列表视图
ListSortedMixin
ListPaginatedMixin
列表视图
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')
【讨论】:
在这种情况下,super(MyListView,self).get_context_data(**context)
与 ListSortedMixin.get_context_data(self, **context)
相同。我认为the previous answer是正确的:我需要一一调用父母函数。
问题是你的mixin没有调用super。即使 mixins 继承自 object
,它们也应该调用 super。 Super 代表 MRO 中的下一个对象(方法解析顺序),这取决于在 MyListView 的声明中指定它们的顺序。我将更新我上面的答案以使其更清楚。
没错。因此,您的示例中调用的方法仅为ListSortedMixin
。我需要手动调用所有的父函数。
super
也会在必要时调用兄弟姐妹。将更新后的代码(更新 2)复制并粘贴到您最喜欢的 Python shell 中,并说服自己相信事实。【参考方案2】:
如果您要做的是按固定顺序调用覆盖的方法。使用此语法:
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
Super 在这种情况下不起作用。参见super(type[, object])
的手册:
返回一个代理对象,它将方法调用委托给父对象或 type 的兄弟类。这对于访问已在类中重写的继承方法很有用。搜索顺序与 getattr() 使用的相同,只是跳过了类型本身。
super 有两个典型用例。在类层次结构中 单继承,super可以用来引用父类 没有明确命名它们,从而使代码更 可维护。这种用法与其他方法中的 super 用法非常相似 编程语言。
第二个用例是支持协作多重继承 动态执行环境。这个用例是 Python 独有的,并且 在静态编译的语言或仅 支持单继承。这使得可以实现 多个基类实现相同的“菱形图” 方法。良好的设计要求此方法具有相同的调用 每种情况下的签名(因为调用的顺序是在 运行时,因为该顺序适应类层次结构的变化, 并且因为该顺序可以包括未知的兄弟类 运行前)。
所以 super 的参数是你想要获取其父类或兄弟类代理的类。 super(ListSortedMixin,self).get_context_data(**context)
不一定会调用 get_context_data
或 ListSortedMixin
。这取决于方法解析顺序 (MRO),您可以使用 print MyListView.__mro__
获得它
所以super()
将调用父级或兄弟级的get_context_data
。执行顺序会适应类层次结构的变化,因为该顺序可以包括在运行之前未知的兄弟类。
【讨论】:
感谢您的快速响应!很好的解释,我现在明白了:)【参考方案3】:我发现大多数 Python 新手并在这里寻找答案的人将使用 Python 3 而不是 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().get_context_data(**kwargs)
class ListPaginatedMixin(object):
def get_context_data(self, **kwargs):
print('ListPaginatedMixin')
return super().get_context_data(**kwargs)
class MyListView(ListSortedMixin, ListPaginatedMixin, Parent):
def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs)
m = MyListView()
m.get_context_data(l='l')
【讨论】:
以上是关于django中的Python多重继承函数覆盖和ListView的主要内容,如果未能解决你的问题,请参考以下文章