🐍 Python - Architecture
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.
- Standard library imports, alphabetically.
- Third party imports , alphabetically.
- Local application specific imports , alphabetically.
- 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:
- Make the target module a package with
__init__.py
. - 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()