🐍 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.
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!
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
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
- Don't use
fromin the import statement.
# 1. after adding `utils` directory and `__init__.py`... from utils import my_function my_function() # 2. import utils utils.my_function()