PyCharm CE 2019.2.3 me advierte sobre una clase en la que almaceno un list de datos junto con los datos de valor type. He intentado reducirlo a la esencia:

class Data:
    def __init__(self, length, data_type):
        assert isinstance(length, int) and length >= 0
        assert isinstance(data_type, type)  # commenting this line out removes the warning
        self._data = [None] * length
        self._data_type = data_type

    def set_field(self, index, value):
        assert isinstance(value, self._data_type)  # commenting this line out removes the warning
        assert isinstance(index, int)
        self._data[index] = value

Recibo una advertencia en el índice:

enter image description here

Tipo (s) inesperado:
(int, tipo)

Tipos posibles:
(int, Ninguno)
(segmento, Iterable [Ninguno])

Información de inspección: esta inspección detecta errores de tipo en las expresiones de llamada de función. Debido al envío dinámico y al tipo de pato, esto es posible en un número limitado pero útil de casos. Los tipos de parámetros de función se pueden especificar en cadenas de documentos o en la anotación de funciones de Python 3.

Más comentarios:

  • eliminar al menos una de las dos afirmaciones marcadas elimina la advertencia

  • es bastante confuso que la advertencia aparezca para el index mientras que las afirmaciones se refieren al value

  • agregar afirmaciones adicionales o cadenas de documentos de sugerencia de tipo no eliminó la advertencia para mí

Mi pregunta: ¿estoy haciendo algo mal con este almacenamiento y afirmación de tipos? ¿Hay alguna razón para esa advertencia y, si no es así, ve una forma conveniente de eliminarla?

2
matheburg 10 oct. 2019 a las 08:07

1 respuesta

La mejor respuesta

El problema aquí es doble:

  • PyCharm tiene un punto ciego (en el momento de escribir este artículo) con respecto al manejo correcto de las metaclases al escribir. Entonces, sin "sugerencias" adicionales, no se puede deducir el tipo correcto para value actualmente.
  • Debido a que inicializó su lista con None, PyCharm la trata como una lista que contiene Nones.

Comencemos con el problema de la metaclase:

Comprueba si data_type es una clase comprobando si es una instancia de type (la metaclase de clases predeterminada). Luego verifica si el value es una instancia de la clase. Esta bien.

Sin embargo, PyCharm asume que su data_type es un type (lo cual es correcto) pero después de isinstance(value, self._data_type) también asume que value es un type (lo cual es incorrecto - debe ser del tipo _data_type). ¡Así que con solo usar assert isinstance(...) con data_type y value PyCharm no podrá deducir el tipo correcto de value!

Entonces, esto probablemente califique como Error o característica faltante en PyCharm, o en cualquier biblioteca que PyCharm use para determinar los tipos.


El segundo problema es que al inicializar _data con None, PyCharm inferirá que el tipo de _data es List[None] (una lista que contiene Nones).

Entonces, si PyCharm deduce algo excepto Any (que puede asignarse a cualquier cosa) o None (que sería el tipo esperado para el contenido de la lista) para value, dará como resultado una advertencia.

Incluso con:

    def set_field(self, index, value):
        assert isinstance(value, int)  # <-- difference
        assert isinstance(index, int)
        self._data[index] = value

Llegará la advertencia.


En este punto tienes dos opciones:

  • Ignora la advertencia.
  • Utilice sugerencias de tipo completas (si las versiones de Python específicas lo permiten).

Si desea usar la sugerencia de tipo, podría usar, por ejemplo:

from typing import List, Optional, TypeVar, Generic, Type

T = TypeVar('T')

class Data(Generic[T]):

    _data: List[Optional[T]]
    _data_type: Type[T]

    def __init__(self, length: int, data_type: Type[T]):
        self._data = [None] * length
        self._data_type = data_type

    def set_field(self, index: int, value: T):
        if isinstance(value, self._data_type):
            self._data[index] = value
        raise TypeError()

Nota: He eliminado las afirmaciones por completo. Si los argumentos no tienen el tipo o valor esperado, un TypeError o ValueError sería más informativo. Sin embargo, en la mayoría de los casos, la documentación y / o las sugerencias de tipo pueden reemplazar adecuadamente assert sy también TypeError s en Python (al menos con un IDE o cuando se usa mypy).

2
MSeifert 14 oct. 2019 a las 17:26