programacion - python clases funciones
Anulación de la función de herencia múltiple de Python y ListView en django (2)
Esta es una pregunta antigua, pero creo que la respuesta es incorrecta. Hay un error en su código. Debe leer:
class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
def get_context_data(self, **context):
super(MyListView,self).get_context_data(**context)
return context
El orden en que se get_context_data
sigue el mismo orden que se especifica en la declaración de MyListView
. Note que el argumento de super es MyListView
y no las súper clases.
ACTUALIZACIÓN :
Extrañé que tus mixins no llamen super. Ellos deberían. Sí, incluso si se heredan de un objeto, porque super llama al siguiente método en la MRO, no necesariamente al padre de la clase en la que se encuentra.
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)
Para MyListView
el MRO es entonces:
- MyListView
- ListaSortedMixin
- ListPaginatedMixin
- Vista de la lista
- Lo que sea que esté por encima de ListView ... n. objeto
Llamarlos uno por uno puede funcionar, pero no es la forma en que se usó.
ACTUALIZACIÓN 2
Copia y pega el ejemplo para probar mi punto.
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'')
get_context_data
una clase que subclasifica ListView
y dos mixins personalizados que han implementado una función get_context_data
. Quería anular esta función en la clase infantil:
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
Cuando ejecuto MyListView
, solo se imprime "ListSortedMixin"
. Por alguna razón, Python está ejecutando ListSortedMixin.get_context_data
en lugar de MyListView.get_context_data
. ¿Por qué?
Si cambio el orden de herencia a ListPaginatedMixin, ListSortedMixin, ListView
, ListPaginatedMixin.get_context_data
se ejecuta.
¿Cómo puedo anular la función get_context_data
?
Si lo que estás tratando de hacer es llamar a métodos sobrescritos en orden fijo. Utilice esta sintaxis:
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 no funcionará en este caso. Consulte el manual de super(type[, object])
:
Devuelva un objeto proxy que delegue las llamadas de método a una clase de tipo padre o hermana. Esto es útil para acceder a los métodos heredados que se han anulado en una clase. El orden de búsqueda es el mismo que el utilizado por getattr (), excepto que se omite el tipo en sí.
Hay dos casos de uso típicos para super. En una jerarquía de clases con herencia única, super se puede usar para referirse a clases primarias sin nombrarlas explícitamente, lo que hace que el código sea más fácil de mantener. Este uso es muy similar al uso de super en otros lenguajes de programación.
El segundo caso de uso es admitir la herencia múltiple cooperativa en un entorno de ejecución dinámico. Este caso de uso es exclusivo de Python y no se encuentra en idiomas compilados de forma estática o en idiomas que solo admiten herencia simple. Esto hace posible implementar "diagramas de diamante" donde varias clases base implementan el mismo método. El buen diseño dicta que este método tenga la misma firma de llamada en todos los casos (porque el orden de las llamadas se determina en tiempo de ejecución, porque ese orden se adapta a los cambios en la jerarquía de clases y porque ese orden puede incluir clases de hermanos que son desconocidas antes del tiempo de ejecución ).
Por lo tanto, el argumento de super es la clase cuyo proxy de clase padre o hermano desea obtener. super(ListSortedMixin,self).get_context_data(**context)
no llamará necesariamente a get_context_data
de ListSortedMixin
. Depende del orden de resolución del método (MRO), que puede obtener utilizando print MyListView.__mro__
Así que super()
llamará a get_context_data
de padre o hermano. El orden de ejecución se adapta a los cambios en la jerarquía de clases y debido a que ese orden puede incluir clases de hermanos que son desconocidas antes del tiempo de ejecución.