¿Cómo puedo decirle a PyCharm qué tipo de parámetro se espera que sea?

173

Cuando se trata de constructores, asignaciones y llamadas a métodos, el IDE de PyCharm es bastante bueno para analizar mi código fuente y descubrir qué tipo debe ser cada variable. Me gusta cuando es correcto, porque me da un buen código completo e información de parámetros, y me da advertencias si intento acceder a un atributo que no existe.

Pero cuando se trata de parámetros, no sabe nada. Los menús desplegables de finalización de código no pueden mostrar nada, porque no saben de qué tipo será el parámetro. El análisis de código no puede buscar advertencias.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

peasant = Person("Dennis", 37)
# PyCharm knows that the "peasant" variable is of type Person
peasant.dig_filth()   # shows warning -- Person doesn't have a dig_filth method

class King:
    def repress(self, peasant):
        # PyCharm has no idea what type the "peasant" parameter should be
        peasant.knock_over()   # no warning even though knock_over doesn't exist

King().repress(peasant)
# Even if I call the method once with a Person instance, PyCharm doesn't
# consider that to mean that the "peasant" parameter should always be a Person

Esto tiene cierto sentido. Otros sitios de llamadas podrían pasar cualquier cosa por ese parámetro. Pero si mi método espera que un parámetro sea de tipo, por ejemplo, pygame.Surfaceme gustaría poder indicarle eso a PyCharm de alguna manera, para que pueda mostrarme todos Surfacelos atributos en su menú desplegable de finalización de código y resaltar advertencias si Llamo al método incorrecto, y así sucesivamente.

¿Hay alguna manera de darle una pista a PyCharm y decir "psst, se supone que este parámetro es de tipo X"? (¿O tal vez, en el espíritu de los lenguajes dinámicos, "se supone que este parámetro grazna como una X"? Estaría bien con eso).


EDITAR: la respuesta de CrazyCoder, a continuación, hace el truco. Para cualquier recién llegado como yo que quiera el resumen rápido, aquí está:

class King:
    def repress(self, peasant):
        """
        Exploit the workers by hanging on to outdated imperialist dogma which
        perpetuates the economic and social differences in our society.

        @type peasant: Person
        @param peasant: Person to repress.
        """
        peasant.knock_over()   # Shows a warning. And there was much rejoicing.

La parte relevante es la @type peasant: Personlínea de la cadena de documentación.

Si también va a Archivo> Configuración> Herramientas integradas de Python y establece "Formato de cadena de documentos" en "Epytext", la Vista de PyCharm> Búsqueda rápida de documentación imprimirá bastante la información del parámetro en lugar de simplemente imprimir todas las líneas @ tal como están.

Joe White
fuente
77
Cabe señalar que el comentario reStructuredText usa las mismas etiquetas recién escritas de forma diferente: se @param xx: yyyconvierte :param xx: yyy. Ver jetbrains.com/pycharm/webhelp/…
Wernight
1
¿Por qué podemos evitar no especificar el nombre de clase completo?
Jesvin Jose

Respuestas:

85

Sí, puede usar un formato de documentación especial para los métodos y sus parámetros para que PyCharm pueda conocer el tipo. La versión reciente de PyCharm admite los formatos de documentos más comunes .

Por ejemplo, PyCharm extrae tipos de comentarios de estilo @param .

Ver también reStructuredText y convenciones de docstring (PEP 257).

Otra opción son las anotaciones de Python 3.

Consulte la sección de documentación de PyCharm para obtener más detalles y muestras.

CrazyCoder
fuente
2
Creo que PyCharm cambió un poco su formato de documento (consulte jetbrains.com/help/pycharm/… ), ¡pero gracias! La falta de inteligencia en los parámetros me estaba volviendo loco.
trozos del
46

Si está utilizando Python 3.0 o posterior, también puede usar anotaciones en funciones y parámetros. PyCharm los interpretará como el tipo que se espera que tengan los argumentos o los valores de retorno:

class King:
    def repress(self, peasant: Person) -> bool:
        peasant.knock_over() # Shows a warning. And there was much rejoicing.

        return peasant.badly_hurt() # Lets say, its not known from here that this method will always return a bool

A veces esto es útil para métodos no públicos, que no necesitan una cadena de documentación. Como beneficio adicional, se puede acceder a esas anotaciones por código:

>>> King.repress.__annotations__
{'peasant': <class '__main__.Person'>, 'return': <class 'bool'>}

Actualización : a partir de PEP 484 , que se ha aceptado para Python 3.5, también es la convención oficial para especificar argumentos y tipos de retorno mediante anotaciones.

Feuermurmel
fuente
44
... y hay varios paquetes que usan tales animaciones para realizar la verificación de tipos en tiempo de ejecución. Esto es más conveniente de usar y más fácil de leer que hacer lo mismo con aserciones y se puede usar selectivamente de la misma manera. typecheck-decoratores uno de esos paquetes y tiene un resumen de los demás en su documentación. (Flexible, también: ¡incluso puedes escribir mecanografiando patos!)
Lutz Prechelt
5

PyCharm extrae tipos de una cadena @type pydoc. Vea los documentos de PyCharm aquí y aquí , y los documentos de Epydoc . Está en la sección 'heredada' de PyCharm, tal vez carece de alguna funcionalidad.

class King:
    def repress(self, peasant):
        """
        Exploit the workers by hanging on to outdated imperialist dogma which
        perpetuates the economic and social differences in our society.

        @type peasant: Person
        @param peasant: Person to repress.
        """
        peasant.knock_over()   # Shows a warning. And there was much rejoicing.

La parte relevante es la @type peasant: Personlínea de la cadena de documentación.

Mi intención no es robar puntos de CrazyCoder o del interrogador original, de ninguna manera darles sus puntos. Solo pensé que la respuesta simple debería estar en un espacio de 'respuesta'.

dfrankow
fuente
2

Estoy usando PyCharm Professional 2016.1 escribiendo código py2.6-2.7, y descubrí que usando reStructuredText puedo expresar los tipos de una manera más sucinta:

class Replicant(object):
    pass


class Hunter(object):
    def retire(self, replicant):
        """ Retire the rogue or non-functional replicant.
        :param Replicant replicant: the replicant to retire.
        """
        replicant.knock_over()  # Shows a warning.

Ver: https://www.jetbrains.com/help/pycharm/2016.1/type-hinting-in-pycharm.html#legacy

pongi
fuente
1

También puede afirmar un tipo y Pycharm lo inferirá:

def my_function(an_int):
    assert isinstance(an_int, int)
    # Pycharm now knows that an_int is of type int
    pass
Alejandro Daniel Noel
fuente