40. Mô-đun và nhập khẩu

Mô-đun là đơn vị tải mã cơ bản, cách ly không gian tên và tái sử dụng của Python. Trong CPython, mô-đun vừa là đối tượng cấp độ ngôn ngữ vừa là bản ghi thời gian chạy trong hệ thống nhập.

Ở cấp độ Python, mô-đun là thứ bạn nhận được sau khi thực thi:python import math import os import json Mỗi tên đã nhập được liên kết với một đối tượng mô-đun, đối tượng gói, hàm, lớp hoặc đối tượng được xuất khác. Ở cấp độ CPython, nhập là một quá trình phối hợp bao gồm các hướng dẫn mã byte, móc nhập, thông số mô-đun, trình tải, công cụ tìm,sys.modules, đường dẫn gói, tra cứu hệ thống tệp, bộ đệm mã byte, khóa nhập và thực thi mô-đun.

Hệ thống nhập không phải là một cơ chế bao gồm tệp đơn giản. Nó là một giao thức thời gian chạy.

40.1 Mô-đun là gì

Một mô-đun là một đối tượng thuộc loạimodule.

import sys

print(type(sys))
print(sys.__name__)
```Đầu ra:```text
<class 'module'>
sys
```Một đối tượng -đun sở hữu một từ điển. Từ điển đó  không gian tên chung của -đun.```python
import math

print(math.__dict__["pi"])
print(math.__dict__["sqrt"])
```Khi CPython thực thi một tệp -đun, các bài tập cấp cao nhất sẽ ghi vào từ điển này.

Đối với một tập tin  tên`config.py`:

```python
debug = True
port = 8080

def connect():
    return port
```CPython tạo một đối tượng -đun, chuẩn bị không gian tên của , thực thi đối tượng  được biên dịch bên trong không gian tên đó  để lại các ràng buộc kết quả trong`config.__dict__`.

Về mặt khái niệm:```text
module object
    __dict__
        "__name__"      -> "config"
        "__file__"      -> ".../config.py"
        "__spec__"      -> ModuleSpec(...)
        "debug"         -> True
        "port"          -> 8080
        "connect"       -> function object
```Do đó, một -đun  một đối tượng không gian tên  thể thay đổi.

## 40.2 Đối tượng mô-đun trong CPython

Trong CPython, các đối tượng -đun được triển khai bởi`PyModuleObject`kiểu.

Một  hình tinh thần đơn giản hóa :```c
typedef struct {
    PyObject_HEAD
    PyObject *md_dict;
    PyObject *md_name;
    PyObject *md_doc;
    PyObject *md_state;
    PyObject *md_weaklist;
    PyModuleDef *md_def;
} PyModuleObject;
```Các trường chính xác  thể thay đổi, nhưng điểm quan trọng  ổn định: một -đun  từ điển liên quan  định nghĩa/trạng thái -đun cấp C tùy chọn.

Từ điển lưu trữ tên Python thông thường. Khi  Python đánh giá tên chung bên trong một -đun, CPython thường tìm trong từ điển -đun đó trước tiên.

 dụ:```python
x = 10

def f():
    return x
```chức năng`f`không sao chép`x`.  lưu trữ một tham chiếu đến từ điển toàn cục của -đun thông qua đối tượng hàm của . Khi`f`thi hành`return x`, CPython giải quyết`x`sử dụng tra cứu toàn cầu đối với từ điển đó.

## 40.3 Nhập là thực thi

Nhập -đun Python sẽ thực thi  cấp cao nhất của .

`example.py`:

```python
print("loading example")

value = 42

def get_value():
    return value
```Lần nhập đầu tiên thực thi tệp:```python
import example
```Đầu ra:```text
loading example
```Lần nhập thứ hai thường không thực thi lại tệp:```python
import example
```Không  đầu ra nào xuất hiện  CPython tìm thấy -đun hiện  trong`sys.modules`.

Hành vi này   bản. Quá trình nhập  tác dụng phụ   cấp cao nhất của -đun chạy.

 cấp cao nhất của -đun tốt thường chứa các định nghĩa  khởi tạo rẻ tiền:```python
CONSTANT = 100

def parse(text):
    ...
``` cấp cao nhất của -đun rủi ro thực hiện công việc tốn kém hoặc  thể nhìn thấy được bên ngoài:```python
connect_to_database()
delete_old_files()
start_threads()
make_network_request()
``` như vậy chạy trong quá trình nhập, đôi khi trước khi ứng dụng được khởi chạy hoàn toàn.

## 40.4 Tuyên bố nhập khẩu

Tuyên bố:```python
import package.module
```không trực tiếp  nghĩa  mở tập tin này.

  nghĩa :```text
resolve a module name
find a module specification
create or reuse a module object
initialize import-related attributes
execute the module if needed
bind a name in the caller's namespace
```Tuyên bố:```python
import os.path
```thường ràng buộc`os`, không`os.path`, trong không gian tên cục bộ:```python
import os.path

print(os)
print(os.path)
```Tuyên bố:```python
from os import path
```ràng buộc`path`trực tiếp:```python
from os import path

print(path)
```Tuyên bố:```python
from math import sqrt
```nhập -đun nếu cần, sau đó truy xuất`sqrt`từ -đun đó  liên kết  trong không gian tên của người gọi.

## 40,5 Mã byte để nhập

CPython biên dịch các câu lệnh nhập thành  byte.

 dụ:```python
import math
``` được biên dịch sử dụng các hướng dẫn  byte liên quan đến nhập. Trình tự hướng dẫn chính xác thay đổi tùy theo phiên bản Python, nhưng về mặt khái niệm,  thực hiện điều này:```text
load import machinery
import module named "math"
bind result to name "math"
```:```python
from math import sqrt
```về mặt khái niệm  byte thực hiện điều này:```text
import module named "math"
load attribute "sqrt"
bind local/global name "sqrt"
```Bạn  thể kiểm tra điều này với`dis`:

```python
import dis

def f():
    import math
    return math.sqrt(9)

dis.dis(f)
```Câu lệnh nhập  một phần của việc thực thi  byte thông thường. Không  bước tiền xử  riêng biệt.

## 40,6`__import__`Ở cấp độ ngôn ngữ, các câu lệnh nhập cuối cùng sẽ định tuyến thông qua bộ máy nhập được hiển thị thông qua`builtins.__import__`.

```python
import builtins

print(builtins.__import__)
```Bạn  thể gọi  trực tiếp:```python
math_module = __import__("math")
print(math_module.sqrt(9))
```Nhưng hầu hết  không nên gọi`__import__`trực tiếp. Sử dụng`importlib.import_module`đối với nhập khẩu động:```python
import importlib

mod = importlib.import_module("math")
print(mod.sqrt(9))
```chức năng`__import__`tồn tại  quá trình nhập  động.  Python  thể nhập -đun theo tên chuỗi khi chạy.

##40.7`sys.modules`

`sys.modules` bộ đệm -đun trung tâm.

  một từ điển ánh xạ tên -đun đủ điều kiện tới các đối tượng -đun.```python
import sys
import math

print(sys.modules["math"] is math)
```Đầu ra:```text
True
```Trước khi tải -đun, hệ thống nhập sẽ kiểm tra`sys.modules`.

Về mặt khái niệm:```python
if fullname in sys.modules:
    return sys.modules[fullname]
else:
    module = load_module(fullname)
    sys.modules[fullname] = module
    return module
```Quá trình thực sự cẩn thận hơn   phải xử  các gói, nhập vòng tròn, nhập không thành công, khóa  giao thức trình tải.

Thuộc tính chính vẫn còn: nội dung nhập được lưu vào bộ đệm theo tên -đun.

## 40.8 Tại sao các mô-đun được chèn trước khi thực thi

CPython thường chèn một -đun vào`sys.modules`trước khi thực thi  của .

Điều này  cần thiết cho việc nhập khẩu tuần hoàn.

Giả định`a.py`chứa:```python
import b

x = 1
````b.py`chứa:```python
import a

y = 2
```Khi`a`nhập khẩu`b`, `b`nhập khẩu`a`, hệ thống nhập phải tránh đệ quy  hạn.  thực hiện điều này bằng cách đặt đối tượng -đun được khởi tạo một phần vào`sys.modules`.

Sự cân bằng  việc nhập khẩu tuần hoàn  thể quan sát các -đun chưa hoàn thiện.

 dụ:```python
# a.py
import b

x = 1
# b.py
import a

print(a.x)
```Điều này  thể thất bại `a.x`vẫn chưa được phân công khi`b`đọc .

Nhập khẩu tuần hoàn không bị cấm, nhưng cần phải thận trọng. Cách khắc phục thông thường  di chuyển nội dung nhập vào bên trong các hàm, di chuyển các định nghĩa được chia sẻ sang -đun thứ ba hoặc tránh sự phụ thuộc chéo cấp cao nhất.

## 40.9 Trình tự khởi tạo mô-đun

Trình tự nhập đơn giản hóa cho -đun nguồn Python trông như thế này:```text
1. Receive module name, such as "pkg.mod".
2. Check sys.modules.
3. Search sys.meta_path for a finder.
4. Finder returns a ModuleSpec.
5. Import machinery creates a module object.
6. Module is inserted into sys.modules.
7. Loader executes module code.
8. Import machinery returns the module object.
9. Import statement binds names in caller namespace.
```Đối với tệp nguồn, việc thực thi  nghĩa :```text
read source
decode source
compile source to code object
execute code object in module namespace
```Đối với -đun mở rộng, việc thực thi  nghĩa  gọi  khởi tạo gốc.

Đối với -đun tích hợp, việc thực thi sử dụng logic khởi tạo tích hợp được biên dịch vào CPython.

## 40.10`ModuleSpec`Sử dụng nhập Python hiện đại`ModuleSpec`các đối tượng để mô tả cách tải một mô-đun.

Thông số -đun chứa thông tin như:```text
module name
loader
origin
package search locations
cached bytecode path
whether the module is a package
```Bạn  thể kiểm tra thông số kỹ thuật của -đun:```python
import json

print(json.__spec__)
print(json.__spec__.name)
print(json.__spec__.origin)
print(json.__spec__.loader)
print(json.__spec__.submodule_search_locations)
```Đối với một -đun bình thường,`submodule_search_locations`thường `None`.

Đối với một gói,  chứa các đường dẫn  thể tìm thấy các -đun con.

## 40.11 Trình tìm kiếm và Trình tải

Hệ thống nhập tách biệt việc tìm kiếm  tải.

Người tìm kiếm trả lời:```text
Can this module name be found?
If yes, what spec describes it?
```Một người tải trả lời:```text
How should this module be created and executed?
```Sự tách biệt này cho phép Python nhập từ nhiều nơi:```text
source files
bytecode files
built-in modules
extension modules
zip archives
namespace packages
custom import hooks
memory-backed module stores
remote systems, if a custom importer implements it
```Hệ thống nhập tiêu chuẩn  thể mở rộng   dựa trên giao thức.

## 40.12`sys.meta_path`

`sys.meta_path` điểm kết nối chính đầu tiên trong hệ thống nhập khẩu.

  một danh sách các đối tượng tìm kiếm. Mỗi công cụ tìm  thể quyết định xem   biết cách xử  tên -đun hay không.```python
import sys

for finder in sys.meta_path:
    print(finder)
```Một tìm kiếm nhập đơn giản thực hiện điều này:```python
for finder in sys.meta_path:
    spec = finder.find_spec(fullname, path, target)
    if spec is not None:
        return spec
```Xử  các mục điển hình:```text
built-in modules
frozen modules
path-based modules
```Công cụ tìm kiếm dựa trên đường dẫn chịu trách nhiệm tìm kiếm các thư mục  các mục nhập đường dẫn khác.

## 40,13`sys.path`

`sys.path` danh sách các vị trí tìm kiếm nhập cho các -đun cấp cao nhất.```python
import sys

for entry in sys.path:
    print(entry)
```Khi bạn viết:```python
import mymodule
````mymodule`không được tích hợp sẵn hoặc bị đóng băng, hệ thống nhập dựa trên đường dẫn sẽ tìm kiếm các mục trong`sys.path`.

Các mục thường :```text
directory of the running script
current working directory in interactive mode
standard library directories
site-packages directories
paths from PYTHONPATH
virtual environment paths
zip archives
```Đây   do tại sao việc thay đổi`sys.path`thay đổi hành vi nhập khẩu.```python
import sys

sys.path.insert(0, "/custom/modules")

import mymodule
```Điều này  thể hữu ích trong các công cụ được kiểm soát nhưng cũng  thể tạo ra hành vi nhập dễ hỏng.

## Gói 40.14

Một gói  một -đun  thể chứa các -đun con.

Về mặt lịch sử, một thư mục đã trở thành một gói bằng cách chứa một`__init__.py`tài liệu:```text
pkg/
    __init__.py
    parser.py
    lexer.py
```Sau đó:```python
import pkg.parser
```tải`pkg`đầu tiên, sau đó`pkg.parser`.

tập tin`pkg/__init__.py`thực thi khi gói được nhập.

 dụ:```python
# pkg/__init__.py
print("loading package")
version = "1.0"
import pkg
print(pkg.version)
```Một gói vẫn  một đối tượng -đun. Sự khác biệt    vị trí tìm kiếm gói.

## 40.15 Thuộc tính gói

Các gói thường xác định các thuộc tính liên quan đến nhập:```text
__name__
__package__
__path__
__spec__
__file__
__cached__
```Thuộc tính quan trọng dành riêng cho gói `__path__`.

```python
import package

print(package.__path__)

__path__cho hệ thống nhập biết nơi tìm kiếm các mô-đun con bên trong gói đó.

Vì:python import package.submodule tìm kiếm hệ thống nhập khẩupackage.__path__, không phải cấp cao nhấtsys.path.

40.16 Gói không gian tên

Python hỗ trợ các gói không gian tên. Đây là những gói không có đơn lẻ__init__.pytài liệu.

Một gói không gian tên có thể được trải rộng trên nhiều thư mục.

Ví dụ:```text dir1/ plugins/ alpha.py

dir2/ plugins/ beta.py ```Nếu cả haidir1dir2đang bậtsys.path, Python có thể xử lýpluginsdưới dạng gói không gian tên.

Sau đó cả hai có thể hoạt động:```python import plugins.alpha import plugins.beta


Chúng cũng làm cho vic nhp d liu tr nên phc tp hơn vì mt gói có th có nhiu v trí tìm kiếm.

## 40.17 Nhập khẩu tuyệt đối

Quá trình nhp tuyt đối bt đầu t không gian tên nhp cp cao nht.```python
import package.module
from package import module
```Bên trong mt gói, nó vn tìm kiếm gói cp cao nht có tên`package`.

Nhp khu tuyt đối được ưu tiên để làm rõ khi đề cp đến các mô-đun bên ngoài hoc cp cao nht.

Ví d:```python
from project.config import Settings
```Điu này cho người đọc biết tên được nhp đến t đâu.

## 40,18 Nhập khẩu tương đối

Vic nhp tương đối được gii quyết da trên gói hin ti.```python
from . import parser
from .lexer import tokenize
from ..config import Settings
```Nhp khu tương đối ph thuc vào`__package__`.

Chúng ch hot động khi mô-đun được thc thi như mt phn ca gói. Đây là lý do ti sao vic chy mô-đun gói trc tiếp dưới dng tp lnh có th phá v quá trình nhp tương đối.

Ví d:```text
project/
    app/
        __init__.py
        main.py
        config.py
```Bên trong`main.py`:

```python
from .config import Settings
```Điu này hot động khi được thc thi vi:```bash
python -m app.main
```Nó có th tht bi khi được thc thi như:```bash
python app/main.py
```bi vì vic thc thi tp lnh trc tiếp s thay đổi cách đặt tên và đóng gói mô-đun.

## 40,19`__main__`Mô-đun được thực thi làm điểm vào chương trình được đặt tên`__main__`.

```python
print(__name__)
```Khi chy dưới dng tp lnh:```bash
python script.py
```Đầu ra:```text
__main__
```Khi nhp khu:```python
import script
```tên mô-đun là:```text
script
```Đây là lý do ti sao các chương trình Python thường s dng:```python
def main():
    ...

if __name__ == "__main__":
    main()
```B phn bo v ngăn không cho mã nhp chương trình chy trong quá trình nhp.

## 40.20 Chạy mô-đun với`-m`Lệnh:```bash
python -m package.module
```chy mô-đun theo tên nhp thay vì theo đường dn tp.

Điu này quan trng vì mô-đun có ng cnh gói chính xác.

Đối vi mã gói, ưu tiên:```bash
python -m package.module
```qua:```bash
python package/module.py
```các`-m`form cho phép hot động nhp tương đối vì CPython biết gói ca mô-đun.

## 40.21 Tệp bộ nhớ đệm mã byte

CPython có th lưu tr mã byte được biên dch trong`__pycache__`.

Ví d:```text
package/
    module.py
    __pycache__/
        module.cpython-312.pyc
```B đệm mã byte tránh biên dch li ngun trong mi ln nhp khi b đệm hp l.

MT`.pyc`tp tin cha:```text
magic number
cache metadata
marshaled code object
```S ma thut xác định phiên bn định dng mã byte. Nó thay đổi khi CPython thay đổi mã byte không tương thích.

CPython kim tra tính hp l ca b đệm bng cách vô hiu hóa da trên du thi gian hoc da trên hàm băm, tùy thuc vào cách to tp.

## 40.22 Mô-đun nguồn và đối tượng mã

Đối vi mt người bình thường`.py`mô-đun, trình ti s biên dch ngun thành mt đối tượng mã.

Sau đó, nó thc thi đối tượng mã trong t đin mô-đun.

V mt khái nim:```python
module = types.ModuleType("example")
code = compile(source_text, filename, "exec")
exec(code, module.__dict__)
```Điu này gn ging vi mô hình thc, mc dù h thng nhp thc tế x lý nhiu chi tiết hơn.

Đim quan trng là vic thc thi mô-đun là thc thi mã thông thường vi t đin mô-đun làm không gian tên chung.

## 40.23 Mô-đun tích hợp

Các mô-đun tích hp được biên dch thành thi gian chy được liên kết hoc thc thi CPython.

Ví d thường bao gm:```python
import sys
import builtins
import time
```Tính kh dng ca mô-đun tích hp ph thuc vào nn tng và cu hình bn dng.

Mt mô-đun tích hp không yêu cu định v mt`.py`tài liu. Trình ti ca nó khi to nó t các định nghĩa cp độ C.

Bn có th kim tra tên mô-đun tích hp:```python
import sys

print(sys.builtin_module_names)
```Các mô-đun tích hp sn cung cp các dch v thi gian chy ct lõi cn thiết trước khi có sn h thng nhp da trên tp đầy đủ.

## 40.24 Mô-đun đông lạnh

Mô-đun c định là các mô-đun Python được nhúng vào mã nh phân CPython dưới dng mã byte c định hoc d liu tĩnh tương đương.

Chúng giúp máy nhp bootstrap trước khi h thng nhp h thng tp hot động đầy đủ.

Điu này to ra mt vn đề khi khi động:```text
importlib implements imports
but importlib itself must be imported
so parts of importlib are frozen
```Các mô-đun c định gii quyết chu trình này bng cách cung cp mã Python đã chn mà không cn nhp tp ngun thông thường.

## 40.25 Mô-đun mở rộng

Các mô-đun m rng là các thư vin chia s gc được ti vào CPython.

Trên các h thng ging Unix, đây thường là`.so`tp tin. Trên Windows, chúng thường`.pyd`tp tin.

Ví d nhp khu:```python
import _sqlite3
import _ssl
import _hashlib
```Mô-đun m rng cung cp chc năng khi to được gi bi CPython. Các mô-đun m rng hin đại s dng khi to nhiu pha khi có th.

Các mô-đun m rng phi tuân theo các quy tc API C ca CPython:```text
create module object
define methods
manage reference ownership
set exceptions on failure
return initialized module
```Vì các mô-đun m rng chy mã gc bên trong quy trình Python nên li có th làm hng trình thông dch.

## 40.26 Khởi tạo một pha và nhiều pha

Các mô-đun m rng cũ hơn thường s dng khi to mt pha. Hàm khi to to và tr v mt đối tượng mô-đun trong mt bước.

Các mô-đun m rng hin đại có th s dng khi to nhiu giai đon. Trong mô hình này, vic to mô-đun và thc thi mô-đun được tách bit.

Điu này phù hp hơn vi ng nghĩa nhp cp độ Python và h tr trng thái trên mi mô-đun rõ ràng hơn.

Khi to nhiu giai đon rt quan trng đối vi:```text
subinterpreter compatibility
module reloading behavior
cleaner module state
avoiding process-global mutable state
future isolation improvements
```Tin ích m rng C lưu tr tt c trng thái trong biến C toàn cc có th hot động trong các trường hp đơn gin, nhưng nó có th hot động kém vi trình thông dch ph hoc khi to lp li.

## 40.27 Khóa nhập

Nhp khu cn khóa.

Nếu không khóa, hai lung có th c gng nhp và khi to cùng mt mô-đun cùng mt lúc.

H thng nhp s dng các khóa để đảm bo rng mt mô-đun không được nhiu lung thc thi đồng thi theo nhng cách không an toàn.

Điu này đặc bit quan trng khi vic khi to mô-đun có tác dng ph:```python
# database.py
connection_pool = create_pool()
```Nếu hai lung được nhp đồng thi mô-đun này mà không khóa, chúng có th to trng thái chung trùng lp hoc quan sát quá trình khi to mt phn.

Khóa nhp ngăn cn nhiu cuc đua như vy.

## 40.28 Tải lại mô-đun

Python có th ti li mô-đun bng cách s dng`importlib.reload`.

```python
import importlib
import config

importlib.reload(config)
```Vic ti li s thc thi li mã mô-đun bng cách s dng đối tượng mô-đun hin có.

Điu này có nhng hu qu tinh tế.

Gi định`config.py`ban đầu cha:```python
value = 1
```Sau khi chnh sa thành:```python
value = 2
```ti li bn cp nht`config.value`.

Nhưng các tài liu tham kho hin có  nơi khác vn có th tr đến các đối tượng cũ.```python
from config import value

import config
import importlib

importlib.reload(config)

print(value)        # old binding
print(config.value) # new module attribute
```Ti li rt hu ích cho các công c phát trin, s ghi chép và h thng plugin nhưng nó không phi là quá trình thiết lp li toàn b quy trình.

## 40.29 Tác dụng phụ khi nhập khẩu

Tác dng ph nhp khu thường là ngun gc ca hành vi khó hiu.

Mô-đun này có tác dng ph rõ ràng:```python
# noisy.py
print("imported noisy")
```Mô-đun này có tác dng ph n:```python
# registry.py
handlers = {}

def register(name, fn):
    handlers[name] = fn
# plugin.py
from registry import register

def handle(x):
    return x

register("plugin", handle)
```Nhập khẩu`plugin`biến đổi`registry.handlers`.

Mẫu này phổ biến trong các hệ thống plugin, ORM, khung kiểm tra  khung web.   thể hữu ích, nhưng   nghĩa  lệnh nhập sẽ trở thành một phần của hành vi chương trình.

## 40.30 Nhập khẩu lười biếng

Quá trình nhập chậm sẽ trì hoãn việc nhập -đun cho đến khi cần.

 dụ:```python
def parse_json(text):
    import json
    return json.loads(text)
```Điều này  thể giảm thời gian khởi động hoặc tránh sự phụ thuộc tùy chọn trong các đường dẫn  không sử dụng.

Nhưng việc nhập khẩu lười biếng  sự đánh đổi:```text
errors appear later
first call may become slower
dependency structure becomes less visible
circular imports may be hidden rather than fixed
```Nhập khẩu lười biếng rất hữu ích khi được sử dụng  chủ ý. Chúng không nên trở thành giải pháp mặc định cho cấu trúc -đun kém.

## 40.31 Nhập khẩu tùy chọn

Nhập tùy chọn  phổ biến để phát hiện tính năng.```python
try:
    import uvloop
except ImportError:
    uvloop = None
```Hãy cẩn thận với việc xử  ngoại lệ rộng. Điều này thường sai:```python
try:
    import plugin
except Exception:
    plugin = None
``` giấu những lỗi thực sự bên trong`plugin`.

Thích bắt hơn`ImportError`hoặc`ModuleNotFoundError`trong phạm vi hẹp  khi cần, hãy xác minh xem -đun nào bị lỗi.```python
try:
    import optional_backend
except ModuleNotFoundError as exc:
    if exc.name != "optional_backend":
        raise
    optional_backend = None
```Điều này tránh việc ẩn các phụ thuộc bắc cầu bị thiếu.

## 40.32 Liên kết tên nhập

Các hình thức nhập khác nhau liên kết các tên khác nhau.

| Tuyên bố | Tên ràng buộc |
|---|---|
|`import os` | `os` |
| `import os.path` | `os` |
| `import os.path as p` | `p` |
| `from os import path` | `path` |
| `from math import sqrt as s` | `s` |
| `from module import *`| nhiều tên |

Hệ thống nhập tải các -đun. Câu lệnh nhập sau đó liên kết các tên trong không gian tên hiện tại.

Đây  những hoạt động liên quan nhưng riêng biệt.

## 40,33 Sao Nhập khẩu

Việc nhập dấu sao sẽ sao chép các tên đã xuất vào không gian tên hiện tại.```python
from module import *
```Nếu -đun xác định`__all__`, Python nhập những tên đó.```python
__all__ = ["connect", "close"]
```Không `__all__`, Python nhập các tên không bắt đầu bằng dấu gạch dưới.

Việc nhập sao thường không được khuyến khích bên ngoài các phiên tương tác  -đun mặt tiền gói  chúng che khuất tên đến từ đâu.

Mặt tiền gói được kiểm soát  thể sử dụng chúng một cách cẩn thận:```python
# package/__init__.py
from .client import Client
from .errors import PackageError

__all__ = ["Client", "PackageError"]
```## 40.34 Mặt tiền trọn gói

Một gói  thể xuất lại tên từ các -đun con.```python
# library/__init__.py
from .client import Client
from .config import Config

__all__ = ["Client", "Config"]
```Sau đó người dùng  thể viết:```python
from library import Client
```thay :```python
from library.client import Client
```Điều này cải thiện tính tiện dụng của API nhưng  thể làm tăng chi phí nhập khẩu. Nếu như`library.__init__`nhập nhiều -đun con nặng, sau đó`import library`trở nên đắt đỏ.

Mặt tiền gói tốt cân bằng giữa sự thuận tiện  chi phí khởi động.

## 40,35 Hiệu suất nhập khẩu

Thời gian nhập rất quan trọng đối với các công cụ dòng lệnh, khởi động nguội máy chủ, kiểm tra  tập lệnh chạy ngắn.

Chi phí nhập khẩu đến từ:```text
file-system searches
source decoding
bytecode validation
compilation if cache is missing
module execution
transitive imports
native extension loading
top-level initialization
```Bạn  thể kiểm tra thời gian nhập bằng:```bash
python -X importtime -c "import your_package"
```Điều này in một cây thời gian nhập.

Các cách phổ biến để cải thiện hiệu suất nhập khẩu:```text
avoid heavy top-level work
delay optional imports
reduce large dependency chains
avoid importing test-only modules at runtime
keep package __init__.py small
avoid broad convenience imports in hot paths
```## 40.36 Lỗi nhập

Các trường hợp ngoại lệ phổ biến liên quan đến nhập khẩu :

| Ngoại lệ | Ý nghĩa |
|---|---|
|`ModuleNotFoundError`| Không thể tìm thấy -đun được yêu cầu |
|`ImportError`| Nhập không thành công   do rộng hơn |
|`AttributeError`| Đã tải -đun nhưng thuộc tính được yêu cầu không tồn tại |
|`SyntaxError`| Không thể biên dịch -đun nguồn |
| Lỗi tải gốc | Không tải được -đun mở rộng |

 dụ:```python
from package import missing_name
```Nếu như`package`tồn tại nhưng`missing_name`không, Python  thể tăng`ImportError`.

 dụ:```python
import missing_package
```Thường tăng:```text
ModuleNotFoundError
```Chẩn đoán lỗi nhập khẩu cần phân biệt:```text
the target module is missing
a transitive dependency is missing
the module exists but raised during execution
the requested exported name is missing
a native extension failed to load
```## 40.37 Nhập khẩu tuần hoàn

Quá trình nhập tuần hoàn xảy ra khi các -đun phụ thuộc vào nhau trong quá trình thực thi cấp cao nhất.

 dụ:```python
# users.py
from posts import Post

class User:
    ...
# posts.py
from users import User

class Post:
    ...
```Điều này  thể thất bại  mỗi -đun cần -đun kia trước khi khởi tạo xong.

Các cách sửa lỗi phổ biến:

1. Chuyển các loại chia sẻ sang -đun thứ ba.```text
models/
    base.py
    users.py
    posts.py
```2. Sử dụng tính năng nhập cục bộ cho các phần phụ thuộc chỉ trong thời gian chạy.```python
def create_post():
    from posts import Post
    return Post()
```3. Sử dụng chú thích loại bị trì hoãn.```python
from __future__ import annotations

class User:
    posts: list[Post]
```4. Phụ thuộc vào giao diện hơn  các -đun cụ thể.

Cách khắc phục tốt nhất thường  về mặt cấu trúc. Nhập khẩu tuần hoàn thường tiết lộ rằng ranh giới -đun được lựa chọn kém.

## 40.38 Kiểm tra nhập và loại

Gợi ý loại  thể tạo chu kỳ nhập nếu chú thích nhập đối tượng thời gian chạy.

Một  hình phổ biến :```python
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from posts import Post

class User:
    def add_post(self, post: "Post") -> None:
        ...

TYPE_CHECKINGlà sai trong thời gian chạy, do đó quá trình nhập sẽ hiển thị với trình kiểm tra loại nhưng bị bỏ qua trong khi thực thi.

Điều này làm giảm chu kỳ nhập thời gian chạy trong khi vẫn giữ thông tin loại.

Python hiện đại cũng hỗ trợ đánh giá chú thích bị trì hoãn trong một số ngữ cảnh, điều này làm giảm hơn nữa việc nhập thời gian chạy để gõ.

40.39 Móc nhập khẩu

Móc nhập cho phép chương trình tùy chỉnh hành vi nhập.

Một công cụ tìm tùy chỉnh có thể được đặt trênsys.meta_path.

Trình tải tùy chỉnh có thể tạo và thực thi các mô-đun từ các nguồn không chuẩn.

Các trường hợp sử dụng bao gồm:text zip import plugin systems test isolation sandboxed module loading import tracing encrypted module stores remote module stores generated modules Bộ xương công cụ tìm tối thiểu trông giống như:```python class Finder: def find_spec(self, fullname, path=None, target=None): if fullname == "virtual_module": ... return None


Móc nhp khu rt mnh m. Chúng nh hưởng đến hot động ca chương trình toàn cu, vì vy chúng phi có phm vi hp và có th d đoán được.

## 40,40`importlib`

`importlib`là giao din thư vin chun cho h thng nhp.

Các thao tác chung:```python
import importlib

mod = importlib.import_module("json")
mod = importlib.reload(mod)
```Các phn cp thp hơn hu ích bao gm:```text
importlib.util.find_spec
importlib.util.module_from_spec
spec.loader.exec_module
importlib.machinery.PathFinder
importlib.machinery.SourceFileLoader
```Ti th công có th trông như thế này:```python
import importlib.util

spec = importlib.util.spec_from_file_location("custom_name", "/path/to/file.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
```Điu này to và thc thi mt mô-đun t mt tp c th.

Đối vi mã ng dng thông thường, hãy ưu tiên nhp khu thông thường. Ch s dng tính năng ti importlib th công khi xây dng công c, h thng plugin, trình ti hoc h thng mô-đun thi gian chy.

## 40.41 Nhận dạng mô-đun

Nhn dng mô-đun da trên khóa trong`sys.modules`.

Nếu cùng mt tp được nhp dưới hai tên khác nhau, CPython có th to hai đối tượng mô-đun riêng bit.

Vn đề ví d:```text
project/
    package/
        __init__.py
        settings.py
```Nếu mt phn ca chương trình nhp:```python
import package.settings
```và mt nguyên nhân thao túng đường dn khác:```python
import settings
```thì cùng mt tp có th được ti hai ln dưới các tên khác nhau.

Điu đó có th nhân đôi toàn cu mô-đun:```text
two registries
two singleton objects
two class identities
two caches
```Đây là mt lý do trc tiếp`sys.path`thao tác có th nguy him.

## 40.42 Mô-đun toàn cầu là trạng thái được chia sẻ

Biến cp mô-đun được chia s bi tt c mã nhp mô-đun.```python
# state.py
count = 0

def increment():
    global count
    count += 1
    return count
```Mi nhà nhp khu đều quan sát cùng mt đối tượng mô-đun:```python
import state

state.increment()
state.increment()
```Điu này rt hu ích cho các hng s, s đăng ký, b đệm và singleton. Nó cũng có th làm cho vic kim tra khó khăn hơn vì trng thái vn tn ti trong các ln nhp khu.

Mt th nghim có th cn phi thiết lp li trng thái mô-đun mt cách rõ ràng:```python
import state

def test_increment():
    state.count = 0
    assert state.increment() == 1
```Hoc cô lp hành vi bng cách tránh các mô-đun toàn cu có th thay đổi.

## 40.43 Cấu hình thời gian nhập

Các mô-đun thường đọc cu hình ti thi đim nhp:```python
import os

DEBUG = os.environ.get("DEBUG") == "1"
```Điu này làm cho cu hình được c định ti thi đim nhp. Nếu môi trường thay đổi sau này,`DEBUG`không t động cp nht.

Thiết kế linh hot hơn s đọc cu hình khi cn:```python
import os

def debug_enabled():
    return os.environ.get("DEBUG") == "1"
```hoc tp trung ti cu hình:```python
class Settings:
    def __init__(self):
        self.debug = os.environ.get("DEBUG") == "1"

settings = Settings()
```Cu hình ti thi đim nhp rt đơn gin nhưng có th gây bt ng cho các bài kim tra và chương trình chy dài.

## 40.44 Cấp độ mô-đun`__getattr__`Các mô-đun có thể xác định`__getattr__`để tùy chỉnh quyền truy cập thuộc tính cho các tên bị thiếu.```python
# package/__init__.py

def __getattr__(name):
    if name == "heavy":
        from . import heavy
        return heavy
    raise AttributeError(name)
```Điu này có th thc hin xut khu lười biếng.

Sau đó:```python
import package

package.heavy
```ch nhp mô-đun con nng khi được yêu cu.

Cp độ mô-đun`__getattr__`rt hu ích cho các miếng chêm tương thích, không dùng na và ti chm. Nó vn đơn gin vì nó thay đổi hành vi truy cp thuc tính thông thường.

## 40,45 Cấp độ mô-đun`__dir__`Một module cũng có thể định nghĩa`__dir__`.

```python
def __dir__():
    return ["Client", "Config", "connect"]
```Điu này kim soát nhng gì xut hin trong:```python
dir(module)
```Nó ch yếu hu ích cho các mô-đun có thuc tính động.

## 40.46 Hệ thống nhập khi khởi động

Trong quá trình khi động CPython, h thng nhp phi được khi to cn thn.

Thi gian chy cn có đủ máy nhp để ti thư vin chun, nhưng phn ln h thng nhp được viết bng Python.

Trình t khi động s dng các mô-đun tích hp và c định để hin th`importlib`.

V mt khái nim:```text
initialize runtime
initialize builtins and sys
initialize frozen importlib bootstrap code
configure import machinery
initialize sys.path
load site if enabled
start executing user code
```Đây là lý do ti sao ni b khi động b hn chế hơn so vi nhp thi gian chy thông thường.

## 40,47`site`và thiết lập môi trường

Sau khi khi to máy móc nhp lõi, CPython thường nhp`site`mô-đun tr khi b vô hiu hóa vi`-S`.

các`site`mô-đun định cu hình các đường dn nhp b sung, bao gm các thư mc gói trang web.

Nó cũng có th x lý:```text
.pth files
user site-packages
virtual environment path adjustments
sitecustomize
usercustomize
```Điu này có nghĩa là môi trường nhp khi khi động ng dng ph thuc vào c trình thông dch, môi trường o, b cc cài đặt và các biến môi trường.

## 40.48 Môi trường ảo và nhập khẩu

Môi trường o thay đổi nơi Python tìm kiếm các gói đã cài đặt.

Nó thường thay đổi:```text
sys.prefix
sys.exec_prefix
site-packages paths
script entry points
```Tp nh phân trình thông dch có th được chia s hoc sao chép, nhưng môi trường nhp s tr đến các thư mc gói ca môi trường o.

Đây là lý do ti sao:```bash
python -m pip install requests
```bên trong mt môi trường o làm cho`requests`ch có th nhp trong môi trường đó.

Bn thân h thng nhp khu cũng vy. Các đường dn tìm kiếm khác nhau.

## 40.49 Nhập từ tệp Zip

Python có th nhp mô-đun t kho lưu tr zip nếu kho lưu tr được bt`sys.path`.

Ví d:```bash
python app.zip
```hoc:```python
import sys

sys.path.insert(0, "modules.zip")
import mymodule
```Nhp Zip s dng trình nhp có th tìm các tp mô-đun bên trong kho lưu tr.

Điu này chng t ti sao vic nhp li da trên mc nhp đường dn thay vì ch da trên thư mc. MT`sys.path`mc nhp có th được x lý bng mt móc đường dn tùy chnh.

## 40.50 Móc đường dẫn và Trình nhập đường dẫn

Đối vi vic nhp da trên đường dn, CPython s dng các móc ni đường dn để chuyn`sys.path`các mc nhp vào các đối tượng nhp khu.

V mt khái nim:```text
sys.path entry
    
sys.path_hooks
    
path importer
    
find module spec
```B đệm`sys.path_importer_cache`lưu tr các đối tượng nhp khu cho các mc nhp đường dn.```python
import sys

print(sys.path_hooks)
print(sys.path_importer_cache)
```Điu này tránh vic xây dng li các đối tượng nhp khu nhiu ln.

## 40.51 Mối lo ngại về bảo mật nhập khẩu

Nhp đường dn tìm kiếm. Điu đó làm cho trt t đường dn tr nên nhy cm v bo mt.

Nếu thư mc hin ti xut hin trước thư vin chun, mt tp cc b có th n mt mô-đun chun.

Ví d:```text
project/
    json.py
```Sau đó:```python
import json
```có th nhp khu địa phương`json.py`thay vì thư vin chun`json`.

Điu này có th gây ra li hoc vn đề bo mt.

Các bin pháp phòng th:```text
avoid naming files after standard library modules
avoid unsafe sys.path insertion
run applications from expected working directories
use virtual environments
inspect module.__file__ when debugging
prefer python -m package.module for package code
```Để kim tra nhng gì đã được nhp khu:```python
import json

print(json.__file__)
```## 40.52 Nhập và thử nghiệm

Các th nghim thường nhn mnh hành vi nhp khu.

Các vn đề kim tra ph biến bao gm:```text
tests depend on working directory
local files shadow installed packages
package imported twice under different names
module global state leaks between tests
environment variables read at import time
plugins register themselves during import
```Thiết lp th nghim mnh m s nhp gói ging như cách người dùng thc hin.

Thích th nghim hành vi gói đã cài đặt:```bash
python -m pytest
```t mt môi trường trong sch, thay vì da vào cách b trí đường dn ngu nhiên.

## 40.53 Nhập khẩu và thiết kế ứng dụng

Cu trúc ng dng Python tt giúp gim độ phc tp khi nhp.

Mt b cc chung:```text
project/
    pyproject.toml
    src/
        app/
            __init__.py
            main.py
            config.py
            service.py
            storage.py
    tests/
        test_service.py
```các`src`b cc giúp nm bt vic nhp ngu nhiên t thư mc gc ca kho lưu tr.

Biu đồ ph thuc mô-đun rõ ràng hướng vào trong:```text
main
    depends on service
service
    depends on storage and config
storage
    depends on database driver
config
    depends on environment parsing
```Tránh các thiết kế trong đó các mô-đun cp thp nhp các đim vào ng dng cp cao.

## 40.54 Nhập khẩu và thiết kế API công khai

B mt nhp ca gói là mt phn ca API công khai.

Ví d:```python
from library import Client
```là mt hp đồng công cng nếu được ghi li.

Vic thay đổi v trí mô-đun ni b s không làm gián đon người dùng nếu mt tin gói duy trì quá trình nhp công khai:```python
# library/__init__.py
from ._client import Client

__all__ = ["Client"]
```Các mô-đun riêng tư thường s dng du gch dưới  đầu:```text
library/
    __init__.py
    _client.py
    _protocol.py
    public.py
```Đây là mt quy ước, không phi là mt hn chế truy cp.

## 40.55 Danh sách kiểm tra gỡ lỗi nhập

Khi hành vi nhp khó hiu, hãy kim tra các giá tr sau:```python
import sys
import module

print(module)
print(module.__name__)
print(getattr(module, "__file__", None))
print(getattr(module, "__spec__", None))
print(getattr(module, "__package__", None))
print(sys.path)
```Đối vi các vn đề v gói:```python
import package

print(package.__path__)
print(package.__spec__.submodule_search_locations)
```Đối vi các vn đề v b đệm:```python
import sys

print(sys.modules.get("module_name"))
```Đối vi thi gian:```bash
python -X importtime -c "import module_name"
```Để gii quyết trc tiếp:```python
import importlib.util

print(importlib.util.find_spec("module_name"))
```## 40.56 Thuật toán nhập tối thiểu

Mt hàm nhp đơn gin có th được viết là:```python
def import_module(fullname):
    if fullname in sys.modules:
        return sys.modules[fullname]

    spec = find_spec(fullname)
    if spec is None:
        raise ModuleNotFoundError(fullname)

    module = module_from_spec(spec)
    sys.modules[fullname] = module

    try:
        spec.loader.exec_module(module)
    except Exception:
        del sys.modules[fullname]
        raise

    return module
```H thng nhp CPython thc s phc tp hơn, nhưng khung này nm bt được lung trung tâm:```text
cache lookup
spec discovery
module creation
cache insertion
module execution
error cleanup
return module
```## 40.57 Lỗi thường gặp: Mô-đun được khởi tạo một phần

Mt li ph biến trông ging như:```text
AttributeError: partially initialized module 'x' has no attribute 'y'
```Điu này thường có nghĩa là s c nhp vòng tròn hoc mô-đun b che khut.

Ví d nhp vòng tròn:```python
# a.py
import b

class A:
    ...
# b.py
import a

class B(a.A):
    ...
```Khi`b`đọc`a.A`, -đun`a`tồn tại `sys.modules`, nhưng lớp của `A`vẫn chưa được xác định.

Cách khắc phục thường   cấu lại các -đun để các định nghĩa lớp không yêu cầu nhập lẫn nhau trong quá trình thực thi cấp cao nhất.

## 40.58 Lỗi thường gặp: Shadowing

Nếu một tệp được đặt tên theo -đun thư viện tiêu chuẩn, quá trình nhập  thể giải quyết sai tệp.

 dụ:```text
random.py
```Bên trong :```python
import random
```Điều này  thể tự nhập thay  thư viện chuẩn`random`.

Các triệu chứng bao gồm:```text
partially initialized module
missing expected attributes
recursive import behavior
strange module.__file__
```Kiểm tra:```python
import random
print(random.__file__)
```Đổi tên tệp cục bộ  xóa các tệp bộ đệm  nếu cần.

## 40.59 Lỗi thường gặp: Chạy trực tiếp tệp gói

Cho:```text
app/
    __init__.py
    main.py
    config.py
```Bên trong`main.py`:

```python
from .config import Settings
```Điều này  thể thất bại:```bash
python app/main.py
```bởi `main.py`được thực thi như`__main__`, không phải như`app.main`.

Sử dụng:```bash
python -m app.main
```từ thư mục chứa`app`.

Điều này bảo tồn bối cảnh gói  làm cho việc nhập tương đối hoạt động.

## 40,60 Điểm chính

-đun  một đối tượng thời gian chạy  từ điển không gian tên.

Việc nhập -đun sẽ thực thi  cấp cao nhất của  một lần cho mỗi tên -đun trong`sys.modules`.

Hệ thống nhập được xây dựng dựa trên công cụ tìm, trình tải, thông số -đun, móc nối đường dẫn  bộ đệm.

Các gói  các -đun  vị trí tìm kiếm -đun con.

Nhập vòng tròn làm lộ các -đun được khởi tạo một phần  CPython chèn các -đun vào`sys.modules`trước khi thực hiện.

Hệ thống nhập khẩu được lập trình thông qua`importlib`, `sys.meta_path`, móc đường dẫn  bộ tải.

Hầu hết các vấn đề về nhập đều xuất phát từ sự phụ thuộc vòng tròn, hiện tượng che khuất đường dẫn, thực thi trực tiếp các tệp gói, tác dụng phụ của thời gian nhập hoặc nhận dạng -đun trùng lặp.