Pythons' Code Style Guide
:material-circle-edit-outline: ็บฆ 1048 ไธชๅญ :fontawesome-solid-code: 114 ่กไปฃ็ :material-clock-time-two-outline: ้ข่ฎก้ ่ฏปๆถ้ด 5 ๅ้
Getting Started
First, follow these steps to structure your repository and maintain consistency:
- Design a Class Diagram: Plan all key classes (e.g., DataLoader, Model, Trainer, TrainingArgs).
- Setting up Style Management Tools: Go to section 1 (Style Management) for instructions.
- Write Class Prototypes: Begin with basic implementations for each class.
- Submit Incremental Pull Requests (PRs): Commit small, meaningful progress and review frequently.
Next, refer to the instructions in each section below when you are writing each of them.
- Style Management
- Commit and Pull Request (PR)
- Prototyping
- File Management
- Imports
- Comments
- Spacing
- Naming
- Type Hints
1 - Style Management
1.1 - Install style checking
Install the pre-commit checking by pip install pre-commit
and add two files at the root directory of your repository.
file .flake8
file .pre-commit-config.yaml
# pre-commit run --all-files
repos:
- repo: https://github.com/pycqa/flake8
rev: 3.7.9
hooks:
- id: flake8
additional_dependencies: [
'flake8-docstrings==1.7.0',
]
and finally, run pre-commit install
.
1.2 - Config the Github repository
Config the branch protection rule to require review on merging each pull request.
According to this document, set up requiring at least one reviewer before merging. Managing a branch protection rule_{target="blank"}
1.3 - Set Up VS Code Style Helpers (Optional)
To streamline code formatting and import sorting, configure VS Code with the following extensions and settings:
-
Install Extensions:
-
Python (for Python language support).
-
isort (for sorting imports).
-
Configure Settings:
To automatically sort the imports and format the code, open the
settings.json
and add or modify the following setting:
2 - Commit and Pull Request (PR)
2.1 - Split Changes into Small PRs
โ Avoid bundling multiple unrelated modifications into a single PR.
โ Each PR should address a single, focused change that can be summarized in one sentence.
Examples: - Pre-commit setup as a standalone PR. - Prototyping or implementing a single class as separate PRs.
2.2 - Ensure Each PR is Complete and Meaningful
โ Avoid submitting partially completed features.
โ Submit only when a feature or change is complete and functional.
2.3 - Manage Committed Files
โ Avoid using git add .
indiscriminately.
โ
Use git add <specific-files>
to ensure only intentional changes are included.
2.4 - Require Review Before Merging
Set up branch protection rules to require reviews before merging. Refer to the GitHub guide: Managing a branch protection rule
2.5 - PR and Commit Messages
PR Titles:
Format titles as you would for commit messages:
[label] name + summary of change
Refer to the Git Commit Style Guide for approved labels.
PR Messages:
The PR description should match the commit message format, providing clear and concise context for the changes.
3 - Prototyping
3.1 - Define Class Prototypes
A prototype is the skeleton of a class, including:
- The class definition.
- Function declarations with proper docstrings.
Example:
class Bar(foo):
def __init__(self, arg: bool) -> None:
"""Comment.
Args:
arg : arg.
"""
pass
def bar(self) -> bool:
"""Comment.
Returns:
arg : arg.
"""
return True
3.2 - Include a Main Function
Itโs encouraged to add a main function to demonstrate the general workflow:
- How classes will be instantiated.
- How functions will be called.
Example:
4 - File Management
4.1 - OOP
Encapsulate each function (except main
) into a related class.
4.2 - Write Prototypes First
Ensure prototypes are written before detailed implementations.
4.3 - Avoid Hyphen or Underscore in File Naming
Use folders to organize files instead of naming files with hyphens or underscores.
โ
Do: models/models.py
โ Don't: models_main.py
Imports
5.1 - Order
- Import all Python standard libraries, in alphabetical order (based on the package name instead of the folder name), and add an empty line.
- Import all 3rd-party libraries, in alphabetical order, and add an empty line.
- Import all libraries defined within the project.
Example:
If you have set up the automatical sorting tool in VSCode, it can avoid you from singing an alphabet song every time you add an import.
5.2 - Importing Names
โ Don't use from x import y
.
โ
The only examptions are those well-established ones, e.g., from typing import Dict, List, Optional, Sequence, Union
.
โ
Do use import x
and x.y
to avoid namespace conflicts, for example:
Comments
6.1 - Where Should Comments Appear?
- File docstring
- Class docstring
- Function docstring
- Other (full-line comment, inline comment)
6.2 - Formats
- Required:
- File docstring (at the top of the file)
- Class docstring (immediately after the class name)
-
Function docstring (immediately after the function name)
-
Docstrings can be either a sentence or multiple paragraphs.
Example for a single sentence:
Example for multiple paragraphs:
-
Function docstring format:
6.3 - File Docstring
Ensure there is no space between the docstring and the imports.
6.4 - Be Sure to Make Every Doc a 'Sentence'
โ
Do # a comment
.
โ Don't # a comment.
.
6.5 - Keep Consistency in Omitting 'The'
โ Do
โ Don't
Spacing
- In every comment: Add 1 empty line between each section.
- Except at the top of the file, do not use more than 2 empty lines.
If you have configured the styling tool in VSCode, it will automatically manage the spacing for you.
Naming
8.1 - Avoid Abbreviations and Use Full Spellings
โ
Do path_checkpoint
.
โ Don't path_ckpt
.
8.2 - Naming Conventions (My Own Habit)
- Class Names: Use a noun-adjective format.
- Function Names: Use a verb-noun format.
- Functions and files that perform similar tasks or operate on the same objects should begin with the same substring.
8.3 - Private Members
Class private members should start with an underscore _ to distinguish them from input parameters.
e.g., the correct private number name should be
instead of
8.4 - Accessing Private Members
Avoid directly accessing private members outside the class.
class Foo:
def __init__(self, bar):
self._bar = bar
def get_bar(self):
return self._bar
foo = Foo()
foo._bar # not recommended, since the members should be 'considered as private'.
foo.get_bar() # not recommended, since the function name looks messy.
Instead, using a @property
decorator is recommonded.
class Foo:
def __init__(self, bar):
self._bar = bar
@property
def bar(self):
return self._bar
foo = Foo()
foo.bar # recommended
Type Hints
9.1 - Write Type Hints
โ Do: write type hints in function declarations.
โ Don't: write types in the comment.
9.2 - Use the typing Library
Use the typing library when you need to indicate the element type of a Dict
, List
, etc.
Commonly used examples:
Dict[x, y]
โ for dictionaries with keys of typex
and values of typey
.Union[x, y, ...]
โ for a type that can be one of several types (e.g.,Union[int, float]
).List[x]
โ for a list where each element is of typex
.Tuple[x, y, ...]
โ for a tuple with fixed types and length.Optional[x]
โ equivalent toUnion[x, None]
, meaning a value could be of typex
orNone
(e.g.,Optional[str]
).Callable[[x, y], z]
โ for a function type that takes arguments of typesx
andy
, and returns a value of typez
.Any
โ for any type (used when you don't want to specify a type).
More examples in typing โ Support for type hints
References and Credits
This code style guide is based on the Google Python Style Guide.
Written with the help of GPT-4o.