es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Requerir explícitamente atributo en descendiente de la clase base de python.

Tengo una clase base abstracta de la cual solo estoy mostrando una pequeña parte aquí, para ilustrar mi problema.

La clase base abstracta “A” a continuación tiene una propiedad “onemore” que utiliza el atributo de instancia “val”. A continuación, hay subclases “B” y “C”, que proporcionan este atributo de formas distintas (pero ambas válidas).

Hasta aquí todo bien:

from abc import ABC, abstractmethod

class A(ABC):
    @property
    def onemore(self) -> int:
        return self.val + 1

class B(A):
    def __init__(self, value):
        self._val = value

    val = property(lambda self: self._val)

class C(A):
    def __init__(self, value):
        self.val = value

b = B(32)
b.onemore  # 33
c = C(54)
c.onemore  # 55

Ahora aquí está mi pregunta: ¿hay alguna manera de definir “A” de tal manera que sea más claro que las subclases deben implementar “val”? Como se define anteriormente, esto es difícil de pasar por alto, especialmente si “A” tiene muchos más métodos.

Intenté esto:

class A(ABC):
    @property
    @abstractmethod
    def val(self) -> int:
        ...

    @property
    def onemore(self) -> int:
        return self.val + 1

Sin embargo, esta definición es demasiado estricta: no quiero exigir que las subclases implementen “val” como una propiedad, solo quiero que lo tengan como un atributo (legible). En otras palabras, quiero que “C” sea una subclase válida, lo cual no es el caso aquí: esta definición no funciona con la forma en que “C” proporciona “self.val” (TypeError: No se puede instanciar una clase abstracta C con el método abstracto val).

¿Alguna idea?

PD: He visto esta pregunta (https://stackoverflow.com/q/2736255/2302262), que es similar, pero no resuelve el TypeError que estoy obteniendo.

Tags:  ,

Answer

  1. Avatar for davy.ai

    Una posible solución para dejar más claro que las subclases necesitan implementar val es definirla como un atributo abstracto en A en lugar de como una propiedad abstracta:

    class A(ABC):
        @property
        def onemore(self) -> int:
            return self.val + 1
    
        @property
        @abstractmethod
        def val(self):
            pass
    

    De esta manera, las subclases deberán definir val como un atributo, pero no será necesario que sea una propiedad. Esto resuelve el problema con C, ya que puede proporcionar val como un atributo de instancia regular. El código actualizado se vería así:

    class B(A):
        def __init__(self, value):
            self._val = value
    
        @property
        def val(self):
            return self._val
    
    
    class C(A):
        def __init__(self, value):
            self.val = value  # Nota: val se define como un atributo de instancia
    
    
    b = B(32)
    print(b.onemore)  # 33
    c = C(54)
    print(c.onemore)  # 55
    

    Esto generará un TypeError si una subclase de A no proporciona un atributo val.

Comments are closed.