Skip to content

Instantly share code, notes, and snippets.

@nafisk
Last active August 12, 2024 21:18
Show Gist options
  • Select an option

  • Save nafisk/8594e7c0eb4d97aea9e17447dbee7b40 to your computer and use it in GitHub Desktop.

Select an option

Save nafisk/8594e7c0eb4d97aea9e17447dbee7b40 to your computer and use it in GitHub Desktop.

Revisions

  1. nafisk revised this gist Aug 12, 2024. 1 changed file with 386 additions and 38 deletions.
    424 changes: 386 additions & 38 deletions PEP8_style_guide.md
    Original file line number Diff line number Diff line change
    @@ -2,14 +2,37 @@

    ## πŸ“ Code Layout

    - **Indentation**: Use 4 spaces per indentation level. No tabs!
    - **Indentation**: Use 4 spaces per indentation level. Continuation lines should align with the opening delimiter or use a hanging indent. Hanging indents should not have arguments on the first line and should further indent to distinguish from the rest.
    ```
    def example():
    if True:
    return
    # Correct:
    def long_function_name(var_one, var_two,
    var_three, var_four):
    print(var_one)
    # Correct (hanging indent):
    def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)
    # Wrong:
    def long_function_name(var_one, var_two,
    var_three, var_four):
    print(var_one)
    ```

    - **Tabs or Spaces**: Spaces are preferred over tabs for indentation. Mixing tabs and spaces is disallowed.
    ```
    # Correct:
    if True:
    print("Spaces for indentation")
    # Wrong:
    if True:
    β†’ print("Tabs for indentation")
    ```

    - **Line Length**: Limit lines to 79 characters for code, and 72 characters for comments and docstrings.
    - **Maximum Line Length**: Limit lines to 79 characters, and 72 characters for comments and docstrings. For teams preferring longer lines, the limit can be extended to 99 characters, provided comments and docstrings are still wrapped at 72 characters.
    ```
    # Correct:
    comment = "This is an example within the length limit."
    @@ -18,18 +41,35 @@
    long_comment = "This line exceeds the recommended maximum length, which is discouraged."
    ```

    - **Blank Lines**: Use 2 blank lines around top-level functions and classes, and 1 blank line around method definitions inside a class.
    - **Blank Lines**: Surround top-level function and class definitions with two blank lines. Use a single blank line to separate method definitions inside a class. Extra blank lines can be used sparingly to separate related code sections.
    ```
    # Correct:
    class MyClass:
    class MyClass:
    def method(self):
    pass
    # Wrong:
    class MyClass:
    def method(self):
    pass
    ```

    - **Source File Encoding**: Always use UTF-8 encoding. Non-ASCII characters should be used sparingly, preferably only for human names or specific data.
    ```
    # Correct:
    # -*- coding: utf-8 -*-
    author = "JosΓ©"
    # Wrong:
    author = "Jos\351" # Non-UTF-8 encoding
    ```

    ## πŸ“¦ Imports

    - **Order and Grouping**: Group imports into three categories: standard library imports, third-party imports, and local imports. Maintain this order, with a blank line between each group.
    - **Import Format**: Imports should be on separate lines. Group imports in the following order: standard library imports, third-party imports, and local imports.
    ```
    # Correct:
    import os
    @@ -38,21 +78,66 @@
    from flask import Flask
    from mymodule import myfunction
    # Wrong:
    import sys, os
    ```

    - **Import Format**: Each import should be on a separate line.
    - **Absolute Imports**: Absolute imports are recommended for clarity and better error handling. Explicit relative imports are acceptable in some cases, particularly in complex package layouts.
    ```
    # Correct:
    import os
    import sys
    from mymodule import myfunction
    # Also Correct (for complex layouts):
    from .mymodule import myfunction
    ```

    - **Wildcard Imports**: Wildcard imports should generally be avoided as they make it unclear which names are present in the namespace.
    ```
    # Correct:
    from math import pi
    # Wrong:
    import sys, os
    from math import *
    # Wrong:
    from mymodule import *
    ```

    ## βšͺ Whitespace
    ## 🧩 Module Level Dunder Names

    - **Avoid Extraneous Whitespace**: Avoid unnecessary spaces around parentheses, brackets, and braces.
    - **Placement**: Module-level β€œdunders” (e.g., `__all__`, `__author__`, `__version__`) should appear after the module docstring but before any import statements, except for `from __future__` imports.
    ```
    """
    This is the example module.
    """
    from __future__ import print_function
    __all__ = ['foo', 'bar']
    __version__ = '1.0'
    __author__ = 'Your Name'
    import os
    ```

    ## πŸ“ String Quotes

    - **Consistency**: Single and double quotes are equivalent in Python; choose one and stick with it. Use triple double quotes for docstrings to align with PEP 257.
    ```
    # Correct:
    name = "John"
    name = 'John'
    # Correct (docstring):
    def foo():
    """This is a docstring."""
    pass
    ```

    ## βšͺ Whitespace in Expressions and Statements

    - **Avoid Extraneous Whitespace**: Avoid unnecessary whitespace inside parentheses, brackets, braces, and before commas, colons, or semicolons.
    ```
    # Correct:
    spam(ham[1], {eggs: 2})
    @@ -61,7 +146,7 @@
    spam( ham[ 1 ], { eggs: 2 } )
    ```

    - **Binary Operators**: Use a single space around binary operators like `=`, `+`, `-`, `*`, `/`, etc.
    - **Binary Operators**: Surround binary operators with a single space on both sides, except when used for alignment.
    ```
    # Correct:
    x = 1 + 2
    @@ -70,7 +155,7 @@
    x=1+2
    ```

    - **Spacing in Slices**: Treat colons in slices as binary operators, with spaces on both sides. In extended slices, omit the space when parameters are missing.
    - **Spacing for Matrix Brackets**: In slices, treat colons as binary operators, with equal spacing on either side. In extended slices with omitted parameters, omit the space around colons:
    ```
    # Correct:
    ham[1:9], ham[1:9:3]
    @@ -79,71 +164,151 @@
    ham[1: 9], ham[1 :9]
    ```

    ## πŸ“ Comments and Docstrings
    - **Function Calls and Indexing**: Do not add space immediately before the open parenthesis that starts the argument list of a function call or indexing/slicing:
    ```
    # Correct:
    spam(1)
    dct['key'] = lst[index]
    # Wrong:
    spam (1)
    dct ['key'] = lst [index]
    ```

    - **Assignment Operators**: Use a single space around assignment operators (`=`) for assignments, except when aligning multiple assignments to improve readability:
    ```
    # Correct:
    x = 1
    y = 2
    # Wrong:
    x = 1
    y = 2
    ```

    ## πŸ“ Comments

    - **Block Comments**: Use full sentences, and align comments with the code they describe.
    - **Block Comments**: Use block comments to explain sections of code, formatted as complete sentences. Each line of a block comment starts with a `#` and a single space.
    ```
    # Correct:
    # This block comment explains the following code section.
    x = x + 1
    # Wrong:
    #This block comment is not properly formatted.
    x = x + 1
    ```

    - **Inline Comments**: Place inline comments on the same line as the statement they describe, separated by at least two spaces.
    - **Inline Comments**: Use inline comments sparingly, separating them from the code by at least two spaces. They should not state the obvious.
    ```
    # Correct:
    x = x + 1 # Increment x
    # Wrong:
    x = x + 1 #Increment x
    # Wrong (obvious):
    x = x + 1 # Add one to x
    ```

    - **Docstrings**: Write docstrings for all public modules, functions, classes, and methods. Use triple double quotes, and keep them concise.
    - **Documentation Strings**: Follow PEP 257 for docstring conventions. Write docstrings for all public modules, functions, classes, and methods. Multiline docstrings should have the closing `"""` on a line by itself.
    ```
    # Correct:
    def foo():
    """Return a foobang."""
    return "foo"
    """
    This is a multiline docstring.
    It describes the function's purpose.
    """
    pass
    # Wrong:
    def foo():
    """This is a one-line docstring."""
    pass
    ```

    ## πŸ”€ Naming Conventions

    - **Variables and Functions**: Use `lower_case_with_underscores` for variable and function names.
    - **Descriptive Names**: Choose descriptive names that convey the purpose of the variable, function, or class.
    ```
    def my_function():
    my_variable = 10
    # Correct:
    def calculate_area(radius):
    pass
    # Wrong:
    def foo(x):
    pass
    ```

    - **Constants**: Use `UPPER_CASE_WITH_UNDERSCORES` for constant values.
    - **Case Styles**: Use `lower_case_with_underscores` for functions and variables, `CapWords` (CamelCase) for classes, and `UPPER_CASE_WITH_UNDERSCORES` for constants.
    ```
    # Correct:
    def my_function():
    my_variable = 10
    class MyClass:
    pass
    MAX_OVERFLOW = 100
    ```

    - **Classes**: Use `CapWords` (CamelCase) for class names.
    - **Underscores**: Use a single leading underscore for non-public methods and instance variables. Use double leading underscores to invoke name mangling for attributes intended to be private in subclasses.
    ```
    # Correct:
    class MyClass:
    pass
    def _private_method(self):
    pass
    class MyClass:
    def __private_method(self):
    pass
    ```

    ## πŸ”§ Best Practices
    ## πŸ”§ Programming Recommendations

    - **Comparison to `None`**: Use `is` or `is not` when comparing to `None`.
    - **Comparison Operators**: Use `is` or `is not` for comparisons to `None`, and `isinstance()` for type checks.
    ```
    # Correct:
    if obj is None:
    pass
    if isinstance(obj, int):
    pass
    # Wrong:
    if obj == None:
    pass
    if type(obj) is int:
    pass
    ```

    - **Type Checking**: Use `isinstance()` for type comparisons rather than comparing types directly.
    - **Boolean Values**: Do not compare boolean values to `True` or `False` using `==`:
    ```
    # Correct:
    if isinstance(obj, int):
    if greeting:
    pass
    # Wrong:
    if type(obj) is int:
    if greeting == True:
    pass
    ```

    - **Return Statements**: Be consistent with return statements within a function. If a function returns a value in some cases, ensure all paths return a value, explicitly using `return None` when necessary.
    ```
    # Correct:
    def foo(x):
    if x >= 0:
    return x
    return None
    - **Avoid `lambda` for Function Assignment**: Prefer `def` statements over `lambda` when assigning functions to variables.
    # Wrong:
    def foo(x):
    if x >= 0:
    return x
    ```

    - **Lambda Expressions**: Prefer `def` over `lambda` for function definitions, as it provides better readability and debugging information.
    ```
    # Correct:
    def add(x, y): return x + y
    @@ -152,14 +317,197 @@
    add = lambda x, y: x + y
    ```

    ## πŸ”’ Public vs. Non-Public Attributes
    ## πŸ”§ Programming Recommendations (continued)

    - **Exception Handling**: Catch specific exceptions rather than using a bare `except:` clause. Use exception chaining appropriately with `raise X from Y`.
    ```
    # Correct:
    try:
    result = x / y
    except ZeroDivisionError:
    print("Division by zero is not allowed.")
    raise
    # Correct (chaining):
    try:
    value = some_function()
    except ValueError as e:
    raise CustomError("An error occurred") from e
    # Wrong:
    try:
    result = x / y
    except:
    print("An error occurred.")
    ```

    - **Context Managers**: Use `with` statements for managing resources to ensure proper cleanup.
    ```
    # Correct:
    with open('file.txt', 'r') as file:
    content = file.read()
    # Wrong:
    file = open('file.txt', 'r')
    try:
    content = file.read()
    finally:
    file.close()
    ```

    - **Function Annotations**: Follow PEP 484 for function annotations. Use PEP 526 for variable annotations, ensuring proper spacing around colons and equal signs:
    ```
    # Correct:
    def munge(input: AnyStr = None):
    pass
    code: int = 123
    - **Public Attributes**: Accessible and stable, with no leading underscores.
    - **Non-Public Attributes**: Subject to change, indicated by a single leading underscore.
    # Wrong:
    def munge(input:AnyStr=None):
    pass
    - **Name Mangling**: Use double leading underscores to avoid name clashes in subclasses, but be mindful of potential debugging challenges.
    code:int = 123
    ```

    ## πŸ› οΈ Designing for Inheritance

    - **Public vs. Non-Public**: Distinguish between public and non-public attributes in classes. Public attributes should be accessible and stable, while non-public attributes are subject to change and should be marked with leading underscores.
    ```
    # Correct:
    class MyClass:
    def public_method(self):
    pass
    def _non_public_method(self):
    pass
    ```

    - **Name Mangling**: Use double leading underscores to avoid name clashes in subclasses, though be cautious of potential drawbacks in debugging and introspection.
    ```
    # Correct:
    class MyClass:
    def __private_method(self):
    pass
    class SubClass(MyClass):
    def __private_method(self):
    pass # This will not override MyClass's __private_method
    ```

    ## 🌐 Public and Internal Interfaces

    - **Public Interfaces**: Documented interfaces are considered public unless explicitly marked otherwise. Use the `__all__` attribute to define the public API of a module.
    ```
    # Correct:
    __all__ = ['public_function', 'PublicClass']
    def public_function():
    pass
    class PublicClass:
    pass
    def _internal_function():
    pass
    ```

    - **Internal Interfaces**: Prefix internal names with a single leading underscore to indicate that they are not part of the public API.
    ```
    # Correct:
    _internal_variable = 42
    def _internal_function():
    pass
    ```

    - **Imported Names**: Imported names should be considered an implementation detail. Other modules should not rely on indirect access to such names unless they are explicitly documented as part of the public API.
    ```
    # Correct:
    from mymodule import _internal_function
    # Usage only within the module that imported it:
    _internal_function()
    ```

    ## πŸ’» Programming Practices

    - **String Methods**: Use `.startswith()` and `.endswith()` instead of slicing for checking prefixes or suffixes.
    ```
    # Correct:
    if filename.startswith('file_'):
    pass
    # Wrong:
    if filename[:5] == 'file_':
    pass
    ```

    - **Type Comparisons**: Use `isinstance()` for type comparisons rather than comparing types directly:
    ```
    # Correct:
    if isinstance(obj, int):
    pass
    # Wrong:
    if type(obj) is int:
    pass
    ```

    - **Sequences**: For sequences (strings, lists, tuples), use the fact that empty sequences are false:
    ```
    # Correct:
    if not seq:
    pass
    # Wrong:
    if len(seq) == 0:
    pass
    ```

    - **Avoid Trailing Whitespace**: Avoid trailing whitespace as it can be confusing and lead to subtle bugs.
    ```
    # Correct:
    message = "Hello, World!"
    # Wrong (note the trailing space after the exclamation point):
    message = "Hello, World! "
    ```

    - **Return in Finally Blocks**: Avoid using `return`, `break`, or `continue` in a `finally` block as it can interfere with exception propagation.
    ```
    # Wrong:
    def foo():
    try:
    return 1
    finally:
    return 2 # This will override the previous return
    ```

    - **Consistent Returns**: Be consistent in the use of `return` statements; if any `return` in a function returns a value, all should, and `return None` should be explicit when no value is returned.
    ```
    # Correct:
    def foo(x):
    if x >= 0:
    return x
    return None
    # Wrong:
    def foo(x):
    if x >= 0:
    return x
    ```

    - **Use of Annotations**: Follow PEP 484 for function and variable annotations. Variable annotations should have proper spacing around colons and equal signs, consistent with the style guide.
    ```
    # Correct:
    def add(a: int, b: int) -> int:
    return a + b
    x: int = 10
    # Wrong:
    def add(a:int,b:int)->int:
    return a + b
    x:int=10
  2. nafisk created this gist Aug 12, 2024.
    165 changes: 165 additions & 0 deletions PEP8_style_guide.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,165 @@
    # PEP 8 – Style Guide for Python Code

    ## πŸ“ Code Layout

    - **Indentation**: Use 4 spaces per indentation level. No tabs!
    ```
    def example():
    if True:
    return
    ```

    - **Line Length**: Limit lines to 79 characters for code, and 72 characters for comments and docstrings.
    ```
    # Correct:
    comment = "This is an example within the length limit."
    # Wrong:
    long_comment = "This line exceeds the recommended maximum length, which is discouraged."
    ```

    - **Blank Lines**: Use 2 blank lines around top-level functions and classes, and 1 blank line around method definitions inside a class.
    ```
    # Correct:
    class MyClass:
    def method(self):
    pass
    ```

    ## πŸ“¦ Imports

    - **Order and Grouping**: Group imports into three categories: standard library imports, third-party imports, and local imports. Maintain this order, with a blank line between each group.
    ```
    # Correct:
    import os
    import sys
    from flask import Flask
    from mymodule import myfunction
    ```

    - **Import Format**: Each import should be on a separate line.
    ```
    # Correct:
    import os
    import sys
    # Wrong:
    import sys, os
    ```

    ## βšͺ Whitespace

    - **Avoid Extraneous Whitespace**: Avoid unnecessary spaces around parentheses, brackets, and braces.
    ```
    # Correct:
    spam(ham[1], {eggs: 2})
    # Wrong:
    spam( ham[ 1 ], { eggs: 2 } )
    ```

    - **Binary Operators**: Use a single space around binary operators like `=`, `+`, `-`, `*`, `/`, etc.
    ```
    # Correct:
    x = 1 + 2
    # Wrong:
    x=1+2
    ```

    - **Spacing in Slices**: Treat colons in slices as binary operators, with spaces on both sides. In extended slices, omit the space when parameters are missing.
    ```
    # Correct:
    ham[1:9], ham[1:9:3]
    # Wrong:
    ham[1: 9], ham[1 :9]
    ```

    ## πŸ“ Comments and Docstrings

    - **Block Comments**: Use full sentences, and align comments with the code they describe.
    ```
    # This block comment explains the following code section.
    x = x + 1
    ```

    - **Inline Comments**: Place inline comments on the same line as the statement they describe, separated by at least two spaces.
    ```
    # Correct:
    x = x + 1 # Increment x
    # Wrong:
    x = x + 1 #Increment x
    ```

    - **Docstrings**: Write docstrings for all public modules, functions, classes, and methods. Use triple double quotes, and keep them concise.
    ```
    # Correct:
    def foo():
    """Return a foobang."""
    return "foo"
    ```

    ## πŸ”€ Naming Conventions

    - **Variables and Functions**: Use `lower_case_with_underscores` for variable and function names.
    ```
    def my_function():
    my_variable = 10
    ```

    - **Constants**: Use `UPPER_CASE_WITH_UNDERSCORES` for constant values.
    ```
    MAX_OVERFLOW = 100
    ```

    - **Classes**: Use `CapWords` (CamelCase) for class names.
    ```
    class MyClass:
    pass
    ```

    ## πŸ”§ Best Practices

    - **Comparison to `None`**: Use `is` or `is not` when comparing to `None`.
    ```
    # Correct:
    if obj is None:
    # Wrong:
    if obj == None:
    ```

    - **Type Checking**: Use `isinstance()` for type comparisons rather than comparing types directly.
    ```
    # Correct:
    if isinstance(obj, int):
    # Wrong:
    if type(obj) is int:
    ```

    - **Avoid `lambda` for Function Assignment**: Prefer `def` statements over `lambda` when assigning functions to variables.
    ```
    # Correct:
    def add(x, y): return x + y
    # Wrong:
    add = lambda x, y: x + y
    ```

    ## πŸ”’ Public vs. Non-Public Attributes

    - **Public Attributes**: Accessible and stable, with no leading underscores.
    - **Non-Public Attributes**: Subject to change, indicated by a single leading underscore.

    - **Name Mangling**: Use double leading underscores to avoid name clashes in subclasses, but be mindful of potential debugging challenges.
    ```
    class MyClass:
    def __private_method(self):
    pass
    ```