¿Existe un consenso sobre lo que debe documentarse en la clase y en las cadenas de documentación de __init__?

12 minutos de lectura

avatar de usuario de causa prima
causa prima

No encontré ninguna mejor práctica sobre lo que debe documentarse en la clase y __init__ cadenas de documentación. A veces encuentro que los argumentos del constructor ya están documentados en la cadena de documentación de la clase, a veces se describen en el __init__ cadena de documentación. Prefiero describir la construcción dentro de la cadena de documentación de la clase, ya que así es como se llama al crear una nueva instancia. Pero lo que se debe documentar en el __init__ métodos docstring entonces?


editar:

sé sobre el guía de estilo de google y el ejemplo de estilo docstring de google, pero ambos no responden a mi pregunta. El ejemplo de estilo docstring dice

Él __init__ El método puede documentarse en la cadena de documentación de nivel de clase o como una cadena de documentación en el __init__ método en sí. Cualquiera de las formas es aceptable, pero las dos no deben mezclarse. Elija una convención para documentar la __init__ método y ser consecuente con él.

Pero si elijo poner la cadena de documentación del __init__ función en la cadena de documentación de nivel de clase, ¿qué debe hacer el __init__ ¿La cadena de documentación contiene?

Avatar de usuario de Eric O Lebigot
Eric O Lebigot

Hay una respuesta oficial, en PEP 257 (el docstring PEP), que podría decirse que tiene autoridad:

El constructor de la clase debe documentarse en la cadena de documentación para su __init__ método.

Esto es bastante lógico, ya que este es el procedimiento habitual para funciones y métodos, y __init__() no es una excepción.

Como consecuencia, esto pone el código y su documentación en el mismo lugar, lo que ayuda al mantenimiento.

Por último, las herramientas que muestran documentación al usuario (como Jupyter o el comando de shell integrado de Python) help()) es más probable que muestren correctamente la documentación de su código. En la práctica, ellos hacer mostrar el __init__() docstring automáticamente cuando solicita ayuda en el clasepor lo que esta es una razón más para seguir la convención oficial de poner la documentación de inicialización en __init__().

  • Afortunadamente, este comentario no es correcto: help(MyClass) muestra todos los métodos de la clase, y __init__() es uno de ellos, por lo que el usuario tiene la información que necesita para crear objetos. Esto es consistente con el requisito oficial. Además, una herramienta como el cuaderno Jupyter hace algo similar cuando solicita los argumentos de un constructor de clase (con shift+tab): muestra tanto la clase y la cadena de documentación de inicio. La moraleja es que seguir alguna convención común es muy útil, especialmente cuando es buena.

    – Eric O Lebigot

    2 de octubre de 2019 a las 9:37


  • Tienes razón, la sugerencia de PEP es bastante buena entonces. Todavía no me gusta tener que desplazarme hasta __init__() en el resultado de la ayuda: nuevamente, esta es una función que el usuario final nunca ve, pero se espera que sepa que está reasignada de manera invisible al nombre de la clase. En términos de legibilidad/obviedad del documento, esto es un poco feo, pero eso es solo programación para ti, supongo. Gracias por la corrección, solo escribiré “ver __init__()” en la cadena de documentación de mi clase para novatos (de los cuales tendré muchos usando mis módulos).

    – Demis

    14 de diciembre de 2019 a las 5:19


  • Tanto Jupyter (a través de MyClass?) y Python (a través de help(MyClass)) muestra automáticamente la cadena de documentación de inicio, por lo que esto debería ser bastante obvio. Dado que es un estándar, es probable que los usuarios también vean esto en muchas otras bibliotecas.

    – Eric O Lebigot

    15 de diciembre de 2019 a las 11:18

  • Adición interesante: Spyder usa automáticamente el contenido de ClassName.__doc__ para la finalización automática de tabulación al instanciar la clase, NO el contenido de ClassName.__init__.__doc__. Así que esto hace que documentar en el clase mucho más útil para el usuario final. Además, como dijeron otros, NumpyDoc también dice que documente el constructor en Class docstring. Por último, help(MyClass) no parece poner el __init__ ayuda en la parte superior, lo que hace que localizar los argumentos del constructor sea irritante.

    – Demis

    16 de diciembre de 2019 a las 5:43


  • Yo diría que tanto Spyder como NumpyDoc pasaron por alto el hecho de que existe una convención, que tiene los resultados no deseados que observaste. personalmente no me importa help(MyClass) poniendo el __init__() docstring en la parte inferior, ya que el comando realmente solicita ayuda sobre la clase y, por lo tanto, la información sobre lo que proporciona la clase debe ser lo primero. Cualquiera que sea la convención que elijan los programas que brindan ayuda, la única forma de obtener un comportamiento bueno y consistente es que todos sigan los estándares.

    – Eric O Lebigot

    19 de diciembre de 2019 a las 12:13

El uso real de la clase se inicializa mediante un comando como SampleClass(args)y ningún usuario va a escribir nunca SampleClass.__init__(args)por lo que desde la perspectiva del usuario final, cuando están confundidos, es mucho más probable que escriban

help(SampleClass)

en vez de

help(SampleClass.__init__)

Así que creo que tiene sentido poner toda la documentación en SampleClassLa cadena de documentación de .
Y en __init__‘s docstring puesto “Por favor mira help(SampleClass) para más información” en caso de que exista la remota posibilidad de que alguien (o algún programa) lo mire.

  • Un usuario señaló que help(SampleClass) TAMBIÉN imprime la ayuda para SampleClass.__init__()pero desafortunadamente Spyder muestra esta línea en la parte inferior de la lista de métodos. En teoría, documentando el constructor en init__() sería adecuado, excepto que sigue siendo confuso ya que nuevamente el usuario nunca ve el término __init__ y debe saber que esto se reasigna de forma invisible a MyClass(args)). En este comentario: stackoverflow.com/questions/37019744/…

    – Demis

    3 de junio de 2021 a las 15:46


avatar de usuario de dshanahan
dshanahan

La documentación de la clase debe incluir la público componentes del objeto. Él __init__ los parámetros pueden o no ser públicos, por lo que si se incluyen en la cadena de documentación de la clase o no, depende del diseño del objeto.

El párrafo completo en PEP 257 estados:

La cadena de documentación de una clase debe resumir su comportamiento y enumerar los métodos públicos y las variables de instancia. Si la clase está destinada a ser subclase y tiene una interfaz adicional para subclases, esta interfaz debe enumerarse por separado (en la cadena de documentación). El constructor de la clase debe documentarse en la cadena de documentación para su __init__
método. Los métodos individuales deben estar documentados por su propia cadena de documentación.

Y el guía de estilo de google estados:

Las clases deben tener una cadena de documentación debajo de la definición de clase que describe la clase. Si su clase tiene atributos públicos, deben documentarse aquí en una sección de Atributos y seguir el mismo formato que la sección Args de una función.

Entonces, la determinación de la documentación depende de si los parámetros para __init__ están público. Si la intención del objeto es que los usuarios construyan sus propias instancias, el __init__ los parámetros deben documentarse en la cadena de documentación de la clase. Sin embargo, si un objeto se construye internamente y luego se devuelve al usuario, la documentación de la clase solo debe hacer referencia a los aspectos públicos del objeto.

Entonces, el siguiente ejemplo de google sugiere que el likes_spam parámetro de __init__ es público:

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

Sin embargo, debajo del público likes_spam el atributo se determina durante __init__ basado en dos parámetros internos spam_count y like_threshold. Asi que, likes_spam está documentado en la cadena de documentación de la clase, mientras que spam_count y like_threshold están documentados en el __init__ cadena de documentación.

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, spam_count, like_threshold=1):
        """Inits SampleClass.

        Args:
            spam_count: The amount of SPAM consumed.
            like_threshold: The threshold consumed that indicates 
                whether we like SPAM.
        """
        self.likes_spam = spam_count > like_threshold
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

avatar de usuario de salomonderossi
salomonderossi

Yo personalmente trato de usar el guía de estilo de google cuando sea posible

Cuando creas una nueva instancia con __init__ debe documentarse qué variables miembro se inicializan. Luego, otras personas saben lo que pueden esperar cuando necesitan acceder a ellos más adelante en su código.

Ejemplo de la guía de estilo de Google:

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

Numpy dice que debes documentar el __init__ en el documento de clase. https://numpydoc.readthedocs.io/en/latest/format.html#docstring-estándar

Aquí hay un ejemplo que puedes ver donde __init__ no tiene una cadena de documentación. En su lugar, aparece en el documento de clase.
https://github.com/numpy/numpy/blob/master/numpy/core/records.py

  • Esto va en contra de la directriz oficial del PEP 257.

    – Eric O Lebigot

    15 de diciembre de 2019 a las 11:22

  • Spyder también va en contra de la directriz oficial, ya que parece que Spyder obtiene su texto de autocompletado de pestañas del claseno la en eso.

    – Demis

    17 de diciembre de 2019 a las 7:33

  • Supongo que deberíamos hacer la pregunta “¿Por qué los paquetes principales con una enorme base de usuarios hacen esto de manera diferente a las pautas PEP 257?” He visto a usuarios de SO referirse a numpy/numpydoc como “estándares”. Tal vez haya una buena razón. ¿Existen otros paquetes que tampoco sigan PEP 257?

    – Demis

    26 de diciembre de 2019 a las 18:24


  • @Demis Spyder me hace algo raro. Si presiono Ctrl+I, obtiene la cadena de documentación de la clase. si uso function? muestra la clase y luego el __call__ docstring, pero si escribo function( muestra una ventana emergente que comienza en el medio de la Returns sección de la cadena de documentación de la clase…

    – endolito

    25 oct 2020 a las 23:00


  • Esta otra pregunta obtuvo algunas respuestas que señalan que Sphinx analiza la cadena de documentación, todavía no entiendo cómo lo hace. stackoverflow.com/review/suggested-edits/25144896

    – Demis

    27 de octubre de 2020 a las 0:19

Avatar de usuario de Oleiade
Oléiada

No tengo conocimiento de ningún consenso sobre ese punto.

sin embargo, el esfinge autodoc módulo permite generar documentación a partir de su cadena de documentación.Por lo tanto, tiende a hacer cumplir cadena de documentación documentación.

En su caso, documentaría lo que el class es y los argumentos del constructor en el class cadena de documentación me gusta:

class MyClass:
    """I am a class.
    I do funny stuff

    :type tags: dict
    :param tags: A dictionary of key-value pairs
    """

    def __init__(tags):
        self.tags = tags

  • Esto va en contra de la directriz oficial del PEP 257.

    – Eric O Lebigot

    15 de diciembre de 2019 a las 11:22

  • Spyder también va en contra de la directriz oficial, ya que parece que Spyder obtiene su texto de autocompletado de pestañas del claseno la en eso.

    – Demis

    17 de diciembre de 2019 a las 7:33

  • Supongo que deberíamos hacer la pregunta “¿Por qué los paquetes principales con una enorme base de usuarios hacen esto de manera diferente a las pautas PEP 257?” He visto a usuarios de SO referirse a numpy/numpydoc como “estándares”. Tal vez haya una buena razón. ¿Existen otros paquetes que tampoco sigan PEP 257?

    – Demis

    26 de diciembre de 2019 a las 18:24


  • @Demis Spyder me hace algo raro. Si presiono Ctrl+I, obtiene la cadena de documentación de la clase. si uso function? muestra la clase y luego el __call__ docstring, pero si escribo function( muestra una ventana emergente que comienza en el medio de la Returns sección de la cadena de documentación de la clase…

    – endolito

    25 oct 2020 a las 23:00


  • Esta otra pregunta obtuvo algunas respuestas que señalan que Sphinx analiza la cadena de documentación, todavía no entiendo cómo lo hace. stackoverflow.com/review/suggested-edits/25144896

    – Demis

    27 de octubre de 2020 a las 0:19

avatar de usuario de coralvanda
coralvanda

Google tiene su propia guía de estilo para Python, que no es mala referencia. Aquí hay un enlace con lo que consideran las mejores prácticas para cadenas de documentos: http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html

  • No responden a mi pregunta, como dije en mi pregunta actualizada.

    – causa prima

    4 de mayo de 2016 a las 8:58

  • De su pregunta actualizada: “Pero si elijo poner la cadena de documentación del en eso función en la cadena de documentación de nivel de clase, ¿qué debe hacer el en eso docstring contiene?” Basado en la guía de estilo, en ese caso, su en eso El método no debe tener una cadena de documentación.

    – coralvanda

    4 de mayo de 2016 a las 9:21

¿Ha sido útil esta solución?