Code Organization in Python

Modular design
Style guidelinesDocumentation

Why readibility matters?

  • Readable code is maintainable: Others (and future you) can understand it.
  • Reduces debugging time: Clear logic = fewer errors.
  • Encourages collaboration: Teams work faster with consistent code.

"Code is read much more often than it is written."PEP 8

Style guidelines

PEP 8 includes a comprehensive list of suggested style guidelines for Python.
PEP 20 provides Python's guiding principles.

💡 Following the style guidelines of a programming language improves the readibility of your code.

⚠️ If a guideline would make the code less readable, do not apply it!

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Style guidelines - general
  1. Use descriptive names

    • Choose variable and functions names that clearly indicate their purpose;

    • Avoid unclear abbreviations unless widely recognized

      👎

      👍

      n

      num_students

      calc_pop_dens()

      calculate_population_density()

  2. Maintain proper code structure

    • Use a consistent indentation and spacing ( 👎 x=5+3 👍 x = 5 + 3)
    • Fix a maximum line lenght
    • Break lines to enhance readability
Style guidelines - general
  1. Comments
    • Explain why, not what: Avoid redundant comments like # Increment counter.
    • Keep comments up to date!

    "Comments that contradict the code are worse than no comments".

  2. Consistency
    • Consistency with a style guide is important.
    • Consistency within a project is more important.
    • Consistency within a module is the most important.
Style guidelines - Python specific

Indentation: 4 spaces (never tabs!).

Line Length: Fix a maximum! PEP8 suggests 79 for code and 72 for docstrings.

There are exception:

  • Long import statements;
  • URLs;
  • pathnames.
Style guidelines - line joining

Avoid explicit line continuation with backslashes (\). Use paratheses (brackets, or braces) for implicit line joining instead:

👎 Bad

my_long_string = "my_long_string is a very, very," \
                 + " very, very long string!"

👍 Good

my_long_string = ("my_long_string is a very, very,"
                  " very, very long string!")
Style guidelines - line joining

👎 Bad

if very_long_condition \
   and something in whatever:
   pass

👍 Good

if (something_very_long
    and something_esle in whatever):
    pass

# Or:
if (
    something_very_long
    and something_esle in whatever
):
    pass
Style guidelines - line joining

Implicit line joining should allign elements vertically, or use a hanging indent:

👎 Bad

long_function_name(var_one, var_two,
    var_three, var_four)

👍 Good

long_function_name(var_one, var_two,
                   var_three, var_four)
# Or:

long_function_name(
    var_one, var_two,
    var_three, var_four,
)
Style guidelines - line joining

Implicit line joining should allign elements vertically, or use a hanging indent:

👎 Bad

my_list = [1, 2, 3
    4, 5, 6]

👍 Good

my_list = [1, 2, 3
           4, 5, 6]

# Or:
my_list = [
    1, 2, 3
    4, 5, 6,
]
Style guidelines - line joining

👎 Bad

def long_function_name(
    var_one, var_two,
    var_three, var_four):
    pass

👍 Good

def long_function_name(var_one, var_two,
                       var_three, var_four):
    pass

# Or:
def long_function_name(
    var_one, var_two,
    var_three, var_four
):
    pass
Style guidelines - Blank lines

Use

  • 2 blank lines: between top-level definitions (functions and classes)
  • 1 blank line: between method definitions inside a class
  • Extra blank lines may be used (sparingly):
    • to separate groups of related functions;
    • in a function to indicate logical sections.
Style guidelines - Imports
  • Always put at the top of the file (after any module comments and docstrings)
  • Group in order: Standard library → Third-party → Local
  • Use as only for name conflicts or standard abbreviations
  • Prefer absolute imports
import os
import sys

import numpy as np
from sklearn.preprocessing import StandardScaler

from mypkg.subpkg import MyClass
Style guidelines - Naming Conventions
  • Variables/functions: snake_case or camelCase.
  • Classes: PascalCase.
  • Constants: ALL_CAPS.
  • modules: alllower.

⚠️ Avoid using Python keywords like if, else, for, class, etc., as variable names.

💡 prefix with underscore:
- _private_var private variables
- __var to invoke name mangling to avoid naming conflicts in subclasses.

Style guidelines

...and much more! 🤯

PEP8: https://peps.python.org/pep-0008/
Google Python Style Guide: https://google.github.io/styleguide/pyguide.html

Style guidelines - Tools for automation

💡

  1. Linters: identify potential errors, bad practices, and style violations (e.g. pylint, flake8, ruff, ...)
  2. Formatters: check stylistic consistency (black, autopep8, ...).
  3. IDE Support:
    • VS Code, PyCharm: Built-in linting/formatting.
  4. Pre-commit Hooks:
    • Automate checks before committing code.
Style guidelines - Ruff

Install ruff:

pip install ruff

To run the linter in the current directory:

ruff check

To resolve automatically the 'fixable' errors:

ruff check --fix

💡 It is always better to use a virtual environment for your project!

💡 Ruff integrates very nicely with git pre-commit

Ruff: https://docs.astral.sh/ruff/