Lo que realmente me gustaría hacer es algo como esto:
class X(metaclass=abc.ABCMeta): @abc.abstractAttribute # this doesn't exist var = [1,2] class Y(X): var = X.var + [3,4] Esto obligaría a cualquier subclase de X a implementar un atributo var estático.
Pero no hay forma de definir un atributo estático como abstracto.
Intentando usar @abc.abstractmethod, combinado con la propiedad, puedo acercarme:
class X(metaclass=abc.ABCMeta): @property @abc.abstractmethod def var(self): return [1,2] class Y(X): @property def var(self): return super().var + [3,4] y=Y(); y.var da [1,2,3,4] como se desee.
Pero el objetivo es crear un atributo/propiedad estático, no un atributo/propiedad de instancia.
Al crear como @staticmethod:
class X(metaclass=abc.ABCMeta): @property @staticmethod @abc.abstractmethod def var(): return [1,2] class Y(X): @property @staticmethod def var(): return X.var + [3,4] ... entonces y=Y(); y.var da TypeError 'staticmethod' object is not callable
Si cambio el orden del decorador, esto resolverá el error invocable del método estático:
class X(metaclass=abc.ABCMeta): @staticmethod @property @abc.abstractmethod def var(): return [1,2] class Y(X): @staticmethod @property def var(): return X.var + [3,4] El método estático funcionará, pero la propiedad no funcionará según lo previsto: y=Y(); y.var devuelve la propiedad en sí, <property at 0x2c16aa1b3b8> .
Esta respuesta está cerca de lo que se desea, pero no funciona en este caso ya que la clase base, X , ya tendrá un atributo var (por lo que la subclase puede acceder a través de super).
¿Cómo se define una clase de python para que tenga un atributo/propiedad abstracto y estático?
Si el requisito de que sea una propiedad es flexible, podría simplemente definir un método abstracto estático:
class X: @staticmethod @abstractmethod def var(): pass class Y(X): @staticmethod def var(): return [1, 2] >>> Y.var() [1, 2]Tal vez una variación de su solución podría funcionar, en lugar de usar dict simplemente probando si las variables estáticas principales y de subclase son el mismo objeto. Funciona para nietos y máquinas tragamonedas, pero la desventaja es que lanzará la excepción si reemplaza Ninguno con Ninguno u otro objeto con el mismo objeto, por lo que no es perfecto.
class X: var = [1,2] def __init_subclass__(cls): if X.var is cls.var: raise NotImplementedError( "Attribute '{}' has not been overriden in class '{}'" \ .format('var', cls.__name__) )Tal vez estoy pasando por alto algo crucial, pero funcionó en casos de uso simples.
Avíseme si conoce una forma más tradicional de resolver esto que también funcione para las clases que usan __slots__ . Pero para mi caso de uso, lo siguiente funcionará:
class X: var = [1,2] def __init_subclass__(cls): attr_name = 'var' if not attr_name in cls.__dict__: raise NotImplementedError( "Attribute '{}' has not been overriden in class '{}'" \ .format(attr_name, cls.__name__) ) class Y(X): # var = X.var + [3,4] # this will work pass # this won't work y = Y()editar: hay otra desventaja de usar este enfoque, que es que esto generará un error incorrecto para los nietos que no anulan:
class Y(X): var = X.var + [3,4] y = Y() # this works class Z(Y): pass z = Z() # this errorsDejaré esta respuesta sin marcar para que alguien sugiera una mejor alternativa.