programming oriented make exercises example python oop scala abstract-class

oriented - Atributos abstractos en Python



python object oriented programming pdf (8)

Python 2.7

Hay un decorador @abstractproperty para esto:

from abc import ABCMeta, abstractmethod, abstractproperty class A: __metaclass__ = ABCMeta def __init__(self): # ... pass @abstractproperty def a(self): pass @abstractmethod def b(self): pass class B(A): a = 1 def b(self): pass

Si no se declara a o b en la clase derivada B generará un TypeError como:

TypeError : no se puede crear una instancia de la clase abstracta B con métodos abstractos a

Python 3.3+

De la documentation :

Obsoleto desde la versión 3.3: ahora es posible usar property , property.getter() , property.setter() y property.deleter() con abstractmethod() , lo que hace que este decorador sea redundante.

El ejemplo anterior esencialmente se convierte en:

from abc import ABCMeta, abstractmethod class A(metaclass=ABCMeta): def __init__(self): # ... pass @property @abstractmethod def a(self): pass @abstractmethod def b(self): pass class B(A): a = 1 def b(self): pass

¿Cuál es la forma más corta / más elegante de implementar el siguiente código Scala con un atributo abstracto en Python?

abstract class Controller { val path: String }

El compilador de Scala impone una subclase de Controller para definir "ruta". Una subclase se vería así:

class MyController extends Controller { override val path = "/home" }


Eche un vistazo al módulo abc (Abtract Base Class): http://docs.python.org/library/abc.html

Sin embargo, en mi opinión, la solución más simple y común es generar una excepción cuando se crea una instancia de la clase base o cuando se accede a su propiedad.


La implementación de Python3.6 podría verse así:

In [20]: class X: ...: def __init_subclass__(cls): ...: if not hasattr(cls, ''required''): ...: raise NotImplementedError In [21]: class Y(X): ...: required =5 ...: In [22]: Y() Out[22]: <__main__.Y at 0x7f08408c9a20>


La respuesta de Bastien Léonard menciona el módulo abstracto de la clase base y la respuesta de Brendan Abel se refiere a los atributos no implementados que generan errores. Para asegurarse de que la clase no se implemente fuera del módulo, puede ponerle un prefijo al subrayado que lo denota como privado para el módulo (es decir, no se importa).

es decir

class _Controller(object): path = '''' # There are better ways to declare attributes - see other answers class MyController(_Controller): path = ''/Home''


Puede crear un atributo en la clase base abstracta abc.ABC con un valor como NotImplemented para que, si el atributo no se invalide y luego se use, se muestre un error en tiempo de ejecución.

El siguiente código utiliza una sugerencia de tipo PEP 484 para ayudar a PyCharm a analizar de forma estática de forma correcta también el tipo de atributo de path .

import abc class Controller(abc.ABC): path = NotImplemented # type: str class MyController(Controller): path = ''/home''


Python tiene una excepción incorporada para esto, aunque no encontrará la excepción hasta el tiempo de ejecución.

class Base(object): @property def path(self): raise NotImplementedError class SubClass(Base): path = ''blah''


Su clase base podría implementar un método __new__ que verifique el atributo de clase:

class Controller(object): def __new__(cls, *args, **kargs): if not hasattr(cls,''path''): raise NotImplementedError("''Controller'' subclasses should have a ''path'' attribute") return object.__new__(cls,*args,**kargs) class C1(Controller): path = 42 class C2(Controller): pass c1 = C1() # ok c2 = C2() # NotImplementedError: ''Controller'' subclasses should have a ''path'' attribute

De esta forma, el error aumenta en instanciación


class AbstractStuff: @property @abc.abstractmethod def some_property(self): pass

A partir de 3.3 abc.abstractproperty está en desuso, creo.