ruk·si

🐍 Python
Architecture

Updated at 2017-01-02 23:22

The most common Python interpreter (CPython) is not internally thread-safe. This is solved with Global Interpreter Lock (GIL), which allows only one thread to execute Python bytecode. That's why a single Python process usually cannot use multiple CPU cores at the same time. All blocking I/O built-in functions release GIL.

Python code consists of modules. A module is a file containing Python definitions and statements. Module name comes from the file name.

module_name.py

Use import to include other modules.

import math
assert math.ceil(1.1) == 2

from math import ceil, floor
assert ceil(2.1) == 3
assert floor(2.1) == 2

Modules run the root scope when loaded. __name__ == '__main__' conditional can be used to check if the module is executed from the command line as the main entry point.

import sys

def main() -> int:
    print('Executed or imported!')
    return 0

if __name__ == '__main__':
    print('Executed!')
    sys.exit(main())
python mymodule.py
# => Executed!
# => Executed or imported!
import mymodule
mymodule.main()
# => Executed or imported!

Prefer as over import *. Use as to differentiate two imports with the same name or to reduce long reference name.

# bad
from numpy import *

# good
import numpy
import numpy as np
from sound.effects import echo as sound_echo
from html.document import echo as doc_echo

Each import should be on a separate line. Easier to read, change and copy.

# bad
import sys, os

# good
import os
import sys
from subprocess import Popen, PIPE

Have a consistent import order. Imports should be grouped in the following order, groups separated by a blank line.

  1. Standard library imports, alphabetically.
  2. Third party imports , alphabetically.
  3. Local application specific imports , alphabetically.
  4. Scope specific imports (lazy importing).

Don't create circular module dependencies. It may cause hard to find bugs.

# a.py
import b

def f() -> int:
    return b.x

print f()
# b.py
import a

x: int = 1

def g():
    print(a.f())
import a  # => 1
import b  # => AttributeError

Don't create modules with the same name as in the standard library. Creating a module like email.py may cause a third party module to use it in stead of the standard library one, causing hard to find bugs.

Modules form packages. __init__.py file is required to make Python treat the directory as a package. It can be just an empty file if no initialization is required.

sound/                          Package for sound processing
      __init__.py               Initialize the "sound" ackage
      formats/                  Subpackage for file format conversions
              __init__.py       Initialize the "formats" subpackage
              wavread.py
      effects/                  Subpackage for sound effects
              __init__.py       Initialize the "effects" subpackage
              echo.py
# usage:
from sound.effects import echo

ImportError: attempted relative import with no known parent package quickfix:

  1. Make the target module a package with __init__.py.
  2. Don't use from in the import statement.
# 1. after adding `utils` directory and `__init__.py`...
from utils import my_function
my_function()

# 2.
import utils
utils.my_function()

Sources