Diferències
Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.
| Ambdós costats versió prèvia Revisió prèvia Següent revisió | Revisió prèvia | ||
| info:cursos:pue:python-pcpp1:m2:4.1 [14/12/2023 11:29] – mate | info:cursos:pue:python-pcpp1:m2:4.1 [19/12/2023 11:02] (actual) – [One-line docstrings] mate | ||
|---|---|---|---|
| Línia 112: | Línia 112: | ||
| * **multi-line docstrings** – they are used for more difficult cases, and should consist of a summary line followed by one blank line and a more elaborate description. | * **multi-line docstrings** – they are used for more difficult cases, and should consist of a summary line followed by one blank line and a more elaborate description. | ||
| Let's talk a bit more about each of them. | Let's talk a bit more about each of them. | ||
| + | |||
| + | === One-line docstrings | ||
| + | **One-line docstrings** should be used for rather simple, obvious, and short descriptions. They should take up one line only, and be surrounded by triple double quotes (the closing quotes should be on the same line as the opening quotes as this helps to keep the code clean and elegant). | ||
| + | |||
| + | Important notes: | ||
| + | |||
| + | * a docstring should begin with an upper-case letter (unless an identifier begins the sentence) and end with a period; | ||
| + | * a docstring should prescribe the code segment' | ||
| + | <code python> | ||
| + | def greeting(name): | ||
| + | """ | ||
| + | return name * 2 | ||
| + | </ | ||
| + | * a docstring should not just simply repeat the function or method parameters. For example: | ||
| + | <code python ❌>def my_function(x, | ||
| + | """ | ||
| + | ...</ | ||
| + | <code python ✔> | ||
| + | def my_function(x, | ||
| + | """ | ||
| + | ...</ | ||
| + | * Do not use a blank line above or under a one-line docstring unless you're documenting a class, in which case you should put a blank line after all the docstrings that document it: | ||
| + | <code python ❌>def calculate_tax(x, | ||
| + | |||
| + | """ | ||
| + | | ||
| + | return (x+y) * 0.25 | ||
| + | </ | ||
| + | === Multi-line docstrings | ||
| + | Multi-line docstrings should be used for non-obvious cases and more detailed descriptions of code segments. They should have a summary line, similar to what a one-line docstring looks like, followed by a blank line and a more elaborate description. The summary line may be located on the same line as the open triple double quotes, or put on the next line. The end quotes should be put on a separate line. | ||
| + | |||
| + | Important notes: | ||
| + | |||
| + | * a multi-line docstring should be indented to the same level as the open quotes, for example: | ||
| + | <code python> | ||
| + | def king_creator(name=" | ||
| + | """ | ||
| + | | ||
| + | Keyword arguments: | ||
| + | :arg name: the king's name (default: Greg) | ||
| + | :type name: str | ||
| + | :arg ordinal: Roman ordinal number (default: I) | ||
| + | :type ordinal: str | ||
| + | :arg country: the country ruled (default: Neverland) | ||
| + | :type country: str | ||
| + | """ | ||
| + | if name == " | ||
| + | return " | ||
| + | ... | ||
| + | </ | ||
| + | * you should insert a blank line after all the multi-line docstrings that are documenting a class; | ||
| + | * script docstrings (in the sense of stand-alone programs/ | ||
| + | * module docstrings should list the classes, exceptions, and functions exported by the module; | ||
| + | * package docstrings (understood as the docstring of the package' | ||
| + | * docstrings for functions and class methods should summarize their behavior and provide information about the arguments (including optional arguments), values, exceptions, restrictions, | ||
| + | * class docstrings should also summarize its behavior as well as document the public methods and instance variables. For example: | ||
| + | <code python> | ||
| + | """ | ||
| + | | ||
| + | Attributes: | ||
| + | ----------- | ||
| + | vehicle_type: | ||
| + | The type of the vehicle, e.g. a car. | ||
| + | id_number: int | ||
| + | The vehicle identification number. | ||
| + | is_autonomous: | ||
| + | self-driving -> True, not self-driving -> False | ||
| + | |||
| + | | ||
| + | Methods: | ||
| + | -------- | ||
| + | report_location(lon=45.00, | ||
| + | Print the vehicle id number and its current location. | ||
| + | (default longitude=45.00, | ||
| + | """ | ||
| + | | ||
| + | def __init__(self, | ||
| + | """ | ||
| + | Parameters: | ||
| + | ----------- | ||
| + | vehicle_type: | ||
| + | The type of the vehicle, e.g. a car. | ||
| + | id_number: int | ||
| + | The vehicle identification number. | ||
| + | is_autonomous: | ||
| + | self-driving -> True (default), not self-driving -> False | ||
| + | """ | ||
| + | | ||
| + | self.vehicle_type = vehicle_type | ||
| + | self.id_number = id_number | ||
| + | self.is_autonomous = is_autonomous | ||
| + | | ||
| + | def report_location(self, | ||
| + | """ | ||
| + | Print the vehicle id number and its current location. | ||
| + | | ||
| + | Parameters: | ||
| + | ----------- | ||
| + | id_number: int | ||
| + | The vehicle identification number. | ||
| + | lon: float, optional | ||
| + | The vehicle' | ||
| + | lat: float, optional | ||
| + | The vehicle' | ||
| + | """ | ||
| + | |||
| + | ... | ||
| + | ... | ||
| + | ... | ||
| + | </ | ||
| + | === Docstring formatting types | ||
| + | You may have noticed that we have used two different docstring formats for documenting the '' | ||
| + | |||
| + | Both formatting types are good for the purposes of creating formal documentation, | ||
| + | |||
| + | Sphinx is a great tool for creating documentation for software development projects. It uses reStructuredText as its markup language, and has a lot of useful features, such as supporting the HTML output format, automatic testing of code snippets, extensive cross-references, | ||
| + | |||
| + | == How to document a project | ||
| + | When documenting a Python project, depending on the nature of the project (i.e. private, shared, public, open source/ | ||
| + | |||
| + | This means you can easily improve their experience by thinking about how they' | ||
| + | |||
| + | Generally, a project should contain the following documentation elements: | ||
| + | |||
| + | * a **readme**, which provides a brief summary of the project, its purpose, and possibly some installation guidelines; | ||
| + | * an **examples.py** file, which is a script that demonstrates a few examples of how to utilize the project; | ||
| + | * a **license** in the form of a txt file (particularly important for Open Source and Public Domain projects) | ||
| + | * a **how to contribute** file which provides information about the possible ways of contributing to the project (shared, open source, and public domain projects). | ||
| + | Because documenting your code can be a rather exhausting and time-consuming activity, you are definitely encouraged to use some of the tools that could help you auto-generate documentation in the desired format, and deal with documentation updates and versioning in an effective and efficient way. | ||
| + | |||
| + | There are many documentation tools and resources available, such as Sphinx, which we've already mentioned, or the highly popular pdoc, and many more. We encourage you to follow this path. | ||
| + | |||
| + | == Linters and fixers | ||
| + | How do you maintain the good quality of your code? Well, you already know that you can follow the style guides such as PEP 8 or PEP 257, and write your code in a readable and consistent way. You can (and possibly should) adopt the Zen of Python philosophy, with all its good advice for writing an elegant and maintainable code, and use the type hinting mechanism. You can observe how others write code and document it as part of their projects (Look at the Python Standard Library or the Requests library), and learn from them. Finally, you can use // | ||
| + | |||
| + | Right. But what is a **linter**? Well, it's a tool that helps you write your code, because it **analyzes it for any stylistic anomalies and programming errors against a set of pre-defined rules**. In other words, it's a program that analyzes your code and reports such issues as structural and syntax errors, consistency breakups, and a lack of compatibility with best practices or code style guidelines such as PEP 8. The most popular linters are: Flake8, Pylint, Pyflakes, Pychecker, Mypy, and Pycodestyle (formerly Pep8) – the official linter tool to check Python code against PEP 8 conventions. | ||
| + | |||
| + | A **fixer**, on the other hand, is a program that helps you fix these issues and format your code to be consistent with the adopted standards. The most popular fixers are: Black, YAPF, and autopep8. | ||
| + | |||
| + | Most editors and IDEs (e.g. PyCharm, Spyder, Atom, Sublime Text, Visual Studio, Eclipse + PyDev, VIM, or Thonny) support linters, which means you can run them in the background as you write code. This makes it possible to detect, highlight, and identify many problem areas in your code, such as typos, wrong tabbing and indentation issues, function calls with the wrong number of arguments, stylistic inconsistencies, | ||
| + | |||
| + | That being said, we encourage you to explore the territory of linters and fixers yourself, and start using them to maintain high-quality Python code, and simply make your life easier. | ||
| + | |||
| + | == How to access docstrings | ||
| + | We've nearly made it to the end of our journey with PEP 257 and docstrings. The last question that still remains to be fully answered is: how can we actually access docstrings? | ||
| + | |||
| + | We do it by using the Python __doc__ attribute – if any string literals are present after the definition of a function/ | ||
| + | |||
| + | Run the code in the editor to see what happens. Your output should be like this:< | ||
| + | |||
| + | A more elaborate description of the function. | ||
| + | |||
| + | Parameters: | ||
| + | a: int (description) | ||
| + | b: int (description) | ||
| + | |||
| + | Returns: | ||
| + | int: Description of the return value.</ | ||
| + | But there' | ||
| + | </ | ||
| + | Run the code and see what happens. What are your conclusions? | ||
| + | |||
| + | As you can see, the output is lengthier and more descriptive:< | ||
| + | |||
| + | my_fun(a, b) | ||
| + | The summary line goes here. | ||
| + | | ||
| + | A more elaborate description of the function. | ||
| + | | ||
| + | Parameters: | ||
| + | a: int (description) | ||
| + | b: int (description) | ||
| + | | ||
| + | Returns: | ||
| + | int: Description of the return value.</ | ||
| + | Now try to access the docstrings of any of the Python built-in functions (e.g. print()). Then import a module and access the module documentation. Experiment with the %%__doc__%% method and the '' | ||
| + | |||
| + | You've learned a lot. You can be proud of yourself! | ||
| + | |||
| + | <code python> | ||
| + | """ | ||
| + | |||
| + | A more elaborate description of the function. | ||
| + | |||
| + | Parameters: | ||
| + | a: int (description) | ||
| + | b: int (description) | ||
| + | |||
| + | Returns: | ||
| + | int: Description of the return value. | ||
| + | """ | ||
| + | return a*b | ||
| + | |||
| + | print(my_fun.__doc__) | ||
| + | </ | ||