0
0
Lập trình
NM

Nắm vững Module, Gói & Namespace trong Python từ Cơ bản đến Nâng cao

Đăng vào 8 tháng trước

• 5 phút đọc

Nắm vững Module, Gói & Namespace trong Python từ Cơ bản đến Nâng cao

Khi bắt đầu học Python, việc sử dụng import có vẻ như một phép màu. Bạn chỉ cần viết import math, và ngay lập tức bạn có thể sử dụng math.sqrt(). Nhưng thực tế, Python đang thực hiện nhiều hơn thế rất nhiều.

Bài viết này là một khám phá sâu về module, gói, và namespace - ba trụ cột của hệ thống nhập khẩu trong Python. Cuối cùng, bạn sẽ không chỉ biết cách sử dụng chúng, mà còn cách chúng hoạt động bên trong, để bạn có thể viết mã Python sạch hơn, nhanh hơn và dễ mở rộng hơn.

🧩 Hiểu về Module - Các Khối Xây Dựng

Module đơn giản là một tệp Python đơn lẻ.

Ví dụ:

python Copy
# greetings.py
def hello(name):
    return f"Hello, {name}!"

Bạn có thể sử dụng nó từ một tệp khác:

python Copy
# app.py
import greetings

print(greetings.hello("Anik"))

Khi bạn chạy app.py, bạn sẽ thấy:

Copy
Hello, Anik!

Điều gì xảy ra khi import?

Khi Python gặp import greetings, đây là những gì thực sự xảy ra:

  1. Kiểm tra bộ nhớ cache của module (sys.modules): Nếu đã được tải, chỉ cần sử dụng lại.
  2. Tìm module: Python tìm kiếm trong sys.path, một danh sách các thư mục:
    • Thư mục làm việc hiện tại
    • Bất kỳ thư mục nào trong PYTHONPATH
    • Thư viện chuẩn
    • Các thư viện bên thứ ba đã cài đặt (site-packages)
  3. Tải và thực thi tệp: Tệp được đọc, biên dịch thành bytecode (.pyc), và thực thi.
  4. Lưu vào bộ nhớ cache trong sys.modules để các lần nhập sau diễn ra ngay lập tức.

Bạn có thể tự kiểm tra điều này:

python Copy
import sys, greetings
print(sys.modules['greetings'])

Điều này sẽ hiển thị một tham chiếu trực tiếp đến đối tượng module đã được tải.

💡 Thông tin thú vị: Đó là lý do tại sao việc nhập cùng một module nhiều lần không thực thi lại mã. Nó chỉ sử dụng lại đối tượng đã được lưu trong bộ nhớ cache.

🔄 Thực thi Module & __name__

Mỗi module có một biến tích hợp __name__.

  • Nếu một tệp đang được chạy trực tiếp, __name__ == "__main__".
  • Nếu nó được nhập như một module, __name__ == "module_name".

Ví dụ:

python Copy
# greetings.py
print(f"Đang chạy như {__name__}")

if __name__ == "__main__":
    print("Điều này chỉ chạy nếu bạn thực thi greetings.py trực tiếp.")

Chạy trực tiếp:

bash Copy
$ python greetings.py
Đang chạy như __main__
Điều này chỉ chạy nếu bạn thực thi greetings.py trực tiếp.

Nhập nó:

python Copy
>>> import greetings
Đang chạy như greetings

Đây là cách mà các thư viện cung cấp cả các hàm có thể nhập khẩu hành vi CLI trong một tệp.

🏗 Ví dụ Thực Tế: Xây dựng một Module Máy Tính

Thay vì viết một script khổng lồ, hãy chia nó thành các module:

Copy
calculator/
    __init__.py
    operations.py
    utils.py
    app.py

operations.py

python Copy
def add(a, b): return a + b
def subtract(a, b): return a - b

utils.py

python Copy
def format_result(value):
    return f"Kết quả: {value}"

app.py

python Copy
from operations import add
from utils import format_result

print(format_result(add(10, 5)))

Kết quả:

Copy
Kết quả: 15

Cấu trúc này dễ bảo trì, kiểm tra và mở rộng khi dự án của bạn phát triển.

🔀 Các Biến Thể Nhập Khẩu (và Khi Nào Sử Dụng Chúng)

Python cung cấp cho bạn nhiều kiểu nhập khẩu:

python Copy
import math             # Nhập đầy đủ
import math as m        # Đặt bí danh
from math import sqrt   # Nhập chọn lọc
from math import *      # Nhập mọi thứ (tránh!)

Thực hành Tốt Nhất

  • ✅ Sử dụng import x hoặc import x as y để rõ ràng.
  • ✅ Sử dụng from x import y chỉ cho một vài tên.
  • ❌ Tránh from x import * vì nó làm ô nhiễm namespace và khiến mã khó đọc hơn.

⚙️ Nhập Khẩu Động với importlib

Đôi khi bạn không biết phải nhập gì cho đến khi chạy. Ví dụ: hệ thống plugin.

python Copy
import importlib

module_name = "math"
math_module = importlib.import_module(module_name)
print(math_module.sqrt(25))

Đây là cách Django tải các ứng dụng một cách động và cách pytest phát hiện các module kiểm tra.

🔄 Tải Lại Các Module

Trong quá trình phát triển, bạn có thể muốn tải lại một module sau khi chỉnh sửa nó.

python Copy
import importlib, greetings
importlib.reload(greetings)

Điều này sẽ thực thi lại mã của module, thay thế các định nghĩa cũ. Hữu ích trong các phiên REPL, nhưng hãy cẩn thận vì nó không thể hoàn toàn đặt lại trạng thái toàn cục.

📦 Bước vào Gói - Tổ chức Các Module của Bạn

Một gói chỉ là một thư mục với tệp __init__.py (tùy chọn trong Python 3.3+).

Ví dụ:

Copy
my_package/
    __init__.py
    module_a.py
    module_b.py

Giờ đây, bạn có thể làm:

python Copy
import my_package.module_a

hoặc

python Copy
from my_package import module_b

__init__.py - Người Kiểm Soát Gói

Bạn có thể để nó trống, hoặc sử dụng nó để xác định những gì gói xuất ra:

python Copy
# __init__.py
from .module_a import function_a
__all__ = ['function_a']

Giờ đây, người dùng chỉ cần làm:

python Copy
from my_package import function_a

🧩 Gói Namespace, Khi Một Thư Mục Không Đủ

Hãy tưởng tượng bạn muốn nhiều nhóm đóng góp vào cùng một gói từ các kho khác nhau. Gói namespace làm điều này trở nên khả thi.

Ví dụ cấu trúc:

Copy
repo1/mypackage/
    a.py
repo2/mypackage/
    b.py

Cả hai thư mục đều được thêm vào sys.path, và bạn có thể làm:

python Copy
import mypackage.a, mypackage.b

Đây là cách mà các thư viện lớn như google.cloud.* hoạt động.

🗂 Thực hành Tốt Nhất cho Cấu trúc Gói

  • Nhóm các chức năng liên quan lại với nhau.
  • Giữ __init__.py sạch sẽ chỉ để xuất lại các hàm/lớp quan trọng.
  • Tránh nhập khẩu vòng (chia mã hoặc sử dụng nhập khẩu cục bộ).
  • Sử dụng nhập khẩu tương đối bên trong các gói (from .module import function).

📦 Nhập Khẩu từ Các Tệp Zip

Python thậm chí có thể nhập trực tiếp từ một tệp .zip:

python Copy
import sys
sys.path.append('my_modules.zip')

import some_module

Hữu ích cho việc vận chuyển các ứng dụng hoặc plugin tự chứa.

🧠 Phía Sau: Bytecode & Bộ Nhớ Cache

Khi Python nhập một module, nó tạo ra một tệp .pyc (bytecode đã biên dịch) trong __pycache__/. Điều này làm cho các lần nhập sau nhanh hơn vì Python bỏ qua việc biên dịch lại.

Bạn có thể kiểm tra bytecode với dis:

python Copy
import dis, greetings
dis.dis(greetings.hello)

Điều này cho thấy các hướng dẫn đã biên dịch, một cách thú vị để nhìn vào bên trong.

🏆 Những Điểm Chính

  • Modules là các tệp .py đơn lẻ; packages là các thư mục chứa module.
  • Các import trong Python được lưu vào sys.modules, vì vậy việc nhập hai lần là miễn phí.
  • __name__ == "__main__" cho phép các tệp hoạt động như cả script và thư viện.
  • importlib cung cấp cho bạn các nhập khẩu động và có thể tải lại.
  • Cấu trúc gói tốt là rất quan trọng cho mã có thể bảo trì.
  • Gói namespace cho phép phát triển gói phân tán.
  • Python có thể nhập từ các thư mục, tệp zip, và thậm chí từ các đường dẫn từ xa (với các công cụ như zipimport).

Hãy bắt đầu áp dụng những kiến thức này vào dự án Python của bạn ngay hôm nay!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào