propiedades programacion poo orientada objetos metodos herencia funciones ejercicios ejemplos ejemplo crear como clases clase atributo python django listview multiple-inheritance django-generic-views

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:

  1. MyListView
  2. ListaSortedMixin
  3. ListPaginatedMixin
  4. Vista de la lista
  5. 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.