Super (), clases base abstractas de Python y NotImplementedError

Las clases base abstractas todavía pueden ser útiles en Python. Al escribir una clase base abstracta donde quiero que cada subclase tenga, digamos, un método de spam() , quiero escribir algo como esto:

 class Abstract(object): def spam(self): raise NotImplementedError 

El desafío también es querer usar super() y hacerlo correctamente al incluirlo en toda la cadena de subclases. En este caso, parece que tengo que envolver cada super llamada como la siguiente:

 class Useful(Abstract): def spam(self): try: super(Useful, self).spam() except NotImplementedError, e: pass print("It's okay.") 

Eso está bien para una subclase simple, pero cuando se escribe una clase que tiene muchos métodos, la cosa try-except se vuelve un poco incómoda y un poco fea. ¿Existe una forma más elegante de subclasificar a partir de clases base abstractas? ¿Lo estoy haciendo mal?

Puedes hacer esto limpiamente en python 2.6+ con el módulo abc :

 import abc class B(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def foo(self): print 'In B' class C(B): def foo(self): super(C, self).foo() print 'In C' C().foo() 

La salida será

 In B In C 

No escriba todo ese código. Una simple inspección de la clase abstracta puede ahorrarle la escritura de todo ese código.

Si el método es abstracto, la subclase concreta no llama super.

Si el método es concreto, la subclase concreta llama super.

El punto clave para entender esto es que super() es para implementar la herencia cooperativa. Cómo cooperan las clases depende de usted el progtwigdor. super() no es mágico y no sabe exactamente lo que quieres! No tiene mucho sentido utilizar super para una jerarquía plana que no necesita herencia cooperativa, por lo que en ese caso la sugerencia de S. Lott es acertada. Las subclases de Útil pueden o no querer usar super() dependiendo de sus objectives 🙂

Por ejemplo: el resumen es A. A <- B, pero luego quiere admitir la inserción de C como A <- C <- B.

 class A(object): """I am an abstract abstraction :)""" def foo(self): raise NotImplementedError('I need to be implemented!') class B(A): """I want to implement A""" def foo(self): print('B: foo') # MRO Stops here, unless super is not A position = self.__class__.__mro__.index if not position(B) + 1 == position(A): super().foo() b = B() b.foo() class C(A): """I want to modify B and all its siblings (see below)""" def foo(self): print('C: foo') # MRO Stops here, unless super is not A position = self.__class__.__mro__.index if not position(C) + 1 == position(A): super().foo() print('') print('B: Old __base__ and __mro__:\n') print('Base:', B.__bases__) print('MRO:', B.__mro__) print('') # __mro__ change implementation B.__bases__ = (C,) print('B: New __base__ and __mro__:\n') print('Base:', B.__bases__) print('MRO:', B.__mro__) print('') b.foo() 

Y la salida:

 B: foo B: Old __base__ and __mro__: Base: (,) MRO: (, , ) B: New __base__ and __mro__: Base: (,) MRO: (, , , ) B: foo C: foo