2011-05-20 731 views
17

frecuencia hago este tipo de cosas:Cuál es la forma correcta para extender un método de la clase padre en Python moderna

class Person(object): 
    def greet(self): 
     print "Hello" 

class Waiter(Person): 
    def greet(self): 
     Person.greet(self) 
     print "Would you like fries with that?" 

La línea Person.greet (auto) no me parece bien. Si alguna vez cambio de qué clase heredará Waiter, voy a tener que rastrear cada uno de estos y reemplazarlos todos.

¿Cuál es la forma correcta de hacerlo es la versión moderna de Python? Tanto 2.x como 3.x, entiendo que hubo cambios en esta área en 3.

Si es importante, generalmente me apego a la herencia individual, pero si se requieren elementos adicionales para acomodar la herencia múltiple correctamente, sería bueno para saber sobre eso.

Respuesta

18

Se utilizan super:

devolver un objeto proxy que los delegados método llama a sus padres o hermanos clase de tipo. Esto es útil para al acceder a métodos heredados que tienen anulados en una clase. El orden de búsqueda es el mismo que el usado por getattr() excepto que se omite el tipo .

En otras palabras, una llamada a super devuelve un objeto falso que delega las búsquedas de atributos a las clases superiores a usted en la cadena de herencia. Puntos a tener en cuenta:

  • Esto no funciona con las clases de estilo antiguo - por lo que si usted está utilizando Python 2.x, es necesario asegurarse de que la clase superior en la jerarquía hereda de object.
  • Debe pasar su propia clase e instancia a super en Python 2.x. Este requerimiento fue renunciado en 3.x.
  • Esto manejará todas las herencias múltiples correctamente. (Cuando se tiene un árbol de herencia múltiple en Python, un method resolution order se genera y las búsquedas de ir a través de las clases padre en este orden.)

Tenga cuidado: hay muchos lugares para conseguir confundido acerca de la herencia múltiple en Python. Es posible que desee leer super() Considered Harmful. Si está seguro de que va a apegarse a un solo árbol de herencia, y que no va a cambiar los nombres de las clases en dicho árbol, puede codificar los nombres de las clases como lo hace arriba y todo funcionará bien.

+1

Aquí hay un enlace de documentación para la versión 3.x de [super()] (http://docs.python.org/py3k/library/functions.html#super). – martineau

+0

Solo para el registro, cuando se refiere a 'Waiter' en la función' super() ', no use el nombre de clase, sino' self .__ class__'. De esta forma, no tendrá que volver a escribir todos sus súper en caso de que cambie el nombre de su clase en el futuro. Me gusta esto (dentro de 'Waiter.greet()'): 'super (self .__ class__, self) .greet()'. –

+0

Me gustaría señalar que a menudo la implementación básica de un método no llamará súper. Por lo tanto, es importante en la herencia múltiple que las clases base para los métodos que está anulando estén más en el MRO que cualquier otra anulación de esos métodos. Esta es la raíz de la regla sobre mixins que se enumeran antes de las bases. Esta condición se garantiza trivialmente si solo hay una clase base y es alcanzable siguiendo al padre más correcto en cada nivel del árbol de herencia. Por ejemplo, si está anulando una clase de Django que sigue a la derecha, los padres siempre deben llevar a la clase de Django. –

8

No estoy seguro de si está buscando esto, pero puede llamar a un padre sin hacer referencia a esto al hacerlo.

super(Waiter, self).greet() 

Esto llamará a la función greet() en Person.

+1

Solo para el registro, también puede usar 'super (self .__ class__, self) .greet() '. De esta forma, en caso de que cambies el nombre de Waiter, no tienes que volver a escribir tus súper. –

3

La respuesta de katrielalex es realmente la respuesta a su pregunta, pero esto no cabría en un comentario.

Si va a ir sobre el uso super todas partes, y cada vez que piensa en términos de herencia múltiple, sin duda leer el "super() Considerado nocivas" enlace. super() es una gran herramienta, pero se necesita comprensión para usarla correctamente.En mi experiencia, para cosas simples que no parecen entrar en complejos enredos de herencia de diamantes, en realidad es más fácil y menos tedioso llamar a la superclase directamente y lidiar con los cambios de nombre cuando cambias el nombre de la clase base.

De hecho, en Python2 debe incluir el nombre de la clase actual, que suele ser más probable que cambie que el nombre de la clase base. (Y de hecho, a veces es muy difícil pasar una referencia a la clase actual si estás haciendo cosas locas: en el momento en que se define el método, la clase no está vinculada a ningún nombre, y en el momento en que super se ejecuta la llamada, el nombre original de la clase aún no puede estar vinculado a la clase, como cuando está usando un decorador de clases)

Cuestiones relacionadas