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.

Tipo de valor de retorno incompatible en el uso genérico de propiedades de Python que devuelve self.

Tratando de implementar una jerarquía de herencia de nodos y árboles que respete “mypy”, tengo las siguientes clases:

from __future__ import annotations
import dataclasses
from typing import Generic, TypeVar, Optional

GenericNodeValue = TypeVar('GenericNodeValue')

@dataclasses.dataclass
class BaseNode(Generic[GenericNodeValue]):
    value: GenericNodeValue
    parent: Optional[BaseNode] = None
    left: Optional[BaseNode] = None
    right: Optional[BaseNode] = None

    @property
    def dummy(self) -> BaseNode:
        return self

GenericNode = TypeVar('GenericNode', bound=BaseNode)

class BaseTree(Generic[GenericNode]):
    def __init__(self):
        self.root: Optional[GenericNode] = None

    def get_dummy(self, node: GenericNode) -> GenericNode:
        return node.dummy

@dataclasses.dataclass
class RedBlackTreeNode(BaseNode[int]):
    red: bool = False

class RedBlackTree(BaseTree[RedBlackTreeNode]):
    def get_dummy2(self, node: RedBlackTreeNode) -> RedBlackTreeNode:
        return node.dummy

Pero “mypy” devuelve un error:

test.py:29: error: Incompatible return value type (got "BaseNode[Any]", expected "GenericNode")
test.py:39: error: Incompatible return value type (got "BaseNode[Any]", expected "RedBlackTreeNode")

¿Hay alguna manera de implementar mi lógica utilizando la escritura de tipos de Python?

Tags:  ,

Answer

  1. Avatar for davy.ai

    Sí, hay algunos cambios que puedes hacer en el código para satisfacer mypy.

    En primer lugar, debes agregar una restricción de tipo a la clase BaseNode para que sus hijos sean del mismo tipo que ella. Esto permitirá a mypy inferir correctamente el tipo de retorno de la propiedad dummy. Puedes hacer esto agregando una variable de tipo ChildNode a BaseNode:

    class BaseNode(Generic[GenericNodeValue, ChildNode]):
        value: GenericNodeValue
        parent: Optional[ChildNode] = None
        left: Optional[ChildNode] = None
        right: Optional[ChildNode] = None
    
        @property
        def dummy(self) -> ChildNode:
            return self
    

    Aquí se usa ChildNode como restricción para el tipo de los atributos parent, left y right de BaseNode. Este cambio permite a mypy inferir el tipo de retorno correcto para la propiedad dummy.

    A continuación, debes agregar una restricción de tipo a BaseTree para especificar el tipo de su atributo root. Puedes hacer esto agregando otra variable de tipo a BaseTree, como en el siguiente ejemplo:

    class BaseTree(Generic[GenericNode, RootNode]):
        def __init__(self):
            self.root: Optional[RootNode] = None
    
        def get_dummy(self, node: GenericNode) -> GenericNode:
            return node.dummy
    

    Aquí, RootNode se utiliza como restricción de tipo para el atributo root, lo que permite a mypy inferir el tipo correcto para node en el método get_dummy.

    Finalmente, debes agregar una restricción de tipo a RedBlackTree para especificar el tipo de su método get_dummy2. Puedes hacer esto especificando el tipo de retorno esperado para este método, como en el siguiente ejemplo:

    class RedBlackTree(BaseTree[RedBlackTreeNode, RedBlackTreeNode]):
        def get_dummy2(self, node: RedBlackTreeNode) -> RedBlackTreeNode:
            return node.dummy
    

    Aquí, RedBlackTreeNode se utiliza para restringir el tipo de retorno de get_dummy2, lo que satisface los requisitos de mypy.

    Con estos cambios, tu código ahora debería pasar las verificaciones de mypy.

Comments are closed.