Học bằng cách đọc theo thứ tự

Module và Package — Import từ các file khác

Học sự khác biệt giữa module, package và library trong Python, cùng cách câu lệnh import kéo các hàm vào từ những file khác.

Ứng dụng Python thường được dựng bằng cách chia công việc ra nhiều file rồi nối chúng lại với nhau. Bài này đi qua các đơn vị gọi là modulepackage, cộng với cách câu lệnh import kéo tính năng từ một file khác vào.

Module vs. Package vs. Library

Python tổ chức code ở ba kích cỡ: module → package → library. Một module là một file .py duy nhất, một package là một folder chứa các module, và một library là cấp tiếp theo lên — một bundle có thể phân phối được.

Phân cấp Module / Package / Library
Module1 file .pyPackageFolder có __init__.pyLibrarypandas / NumPy / v.v.gomship như
File (module) gom thành folder (package), và nhiều package được phân phối cùng nhau như một library (pandas, NumPy, v.v.).
Đơn vịLà gìVí dụ
Module1 file .pymath_utility.py
PackageFolder chứa __init__.pymy_app/database/
LibraryBản phân phối của một hoặc nhiều packagepandas / NumPy / requests

Standard Library vs. Third-Party Library

Python đi kèm với một standard library ngay từ đầu, và còn có các third-party library mà bạn cài thêm. Những thứ chuẩn như math, os, và json chỉ cần import là dùng. Còn third-party như pandas hay requests cần pip install package_name trước.

LoạiCài đặtVí dụ
Standard libraryĐi kèm Python (không cần cài)math / os / sys / json / datetime
Third-party libraryThêm qua pip installpandas / numpy / requests

Thử thư viện chuẩn math.

① In ra trần số nguyên của 1.7 với math.ceil(1.7).

② In căn bậc hai của 3 với math.sqrt(3).

(Khi chạy đúng, phần giải thích sẽ hiện ra phía dưới.)

Python Editor

Chạy code để xem đầu ra

Import module của riêng bạn

Bạn có thể import các file .py của mình giống như standard library. Khi chạy Python local, đặt main.py và file bạn muốn import (math_utility.py) vào cùng một folder — vậy là xong. File trong cùng folder load chỉ với import math_utility từ main.py (không cần đuôi .py trong câu lệnh import).

Bố cục local (file đặt cạnh nhau)
my_project/ ← folder dự án
  • main.py — entry point. Bắt đầu với import math_utility
  • math_utility.py — module định nghĩa add() / multiply()
Đặt main.py và math_utility.py trong cùng một folder. Python kiểm tra folder của file đang chạy trước, nên import math_utility tìm thấy hàng xóm ngay lập tức — không cần subfolder.
Từ import đến gọi hàm
main.pyimport math_utilityPython loadfile từcùng foldermath_utility.add()math_utility.multiply()gọi đượcloadxong
Khi import math_utility chạy, Python load math_utility.py từ cùng folder. Sau đó, bạn có thể gọi các hàm của nó như math_utility.add(...) với tên module đứng trước.

math_utility.py được đính kèm bên trái (mở từ 📂 Files để xem).

① Load nó với import math_utility.

Cố tình gọi add(10, 20) mà không có tiền tố tên module và xác nhận với try/except rằng bạn nhận được NameErrorimport math_utility chỉ đưa chính tên math_utility vào scope của main, nên add không gọi trực tiếp được.

③ Sau đó in math_utility.add(10, 20)math_utility.multiply(5, 5) với tiền tố tên module — cách gọi đúng.

Python Editor

Chạy code để xem đầu ra

import chạy toàn bộ file một lần

Khi bạn viết import math_utility, Python thực thi math_utility.py từ trên xuống dưới một lần. Định nghĩa hàm (def) được đăng ký vào bộ nhớ ngay lúc đó, nên sau này bạn có thể gọi chúng như math_utility.add(...). Thân của các hàm đó không chạy lúc import — chỉ code bên ngoài bất kỳ hàm nào (top level của module) chạy.

Việc load file bên ngoài trông như thế nào
main.pyimport math_utilitymath_utility.pychạy từ trên xuốngmath_utility.add()gọi đượcloadsau đó
Ngay khi main.py gặp import math_utility, Python chạy math_utility.py từ trên xuống dưới. Định nghĩa def được đăng ký vào bộ nhớ và sau đó gọi được như math_utility.add(...).

Đừng chạy việc nặng ở top level của module

Top level nghĩa là code nằm ở mức indent ngoài cùng — bên ngoài bất kỳ hàm hay class nào. Python chạy nó từ trên xuống dưới mỗi khi module được import. Đặt việc nặng ở đó (kết nối DB, load file lớn, vòng lặp vô hạn) nghĩa là chỉ riêng việc import module đã mất rất lâu. Giữ logic nặng bên trong các hàm và chỉ để định nghĩa cùng khởi tạo tối thiểu ở top level.

Phân biệt chạy trực tiếp với import — __name__

File Python có hai dạng: script chạy trực tiếp (bạn chạy với python xxx.py) và module được file khác import. Cùng một file có thể đóng cả hai vai trò, và bạn thường cần biết cái nào đang xảy ra — ví dụ, "chỉ chạy smoke test khi file được chạy trực tiếp".

Việc kiểm tra dùng biến đặc biệt __name__ mà Python tự đặt. Khi file được chạy trực tiếp, __name__"__main__". Khi file được import, __name__ là tên module (tên file). Code bên trong if __name__ == "__main__": chỉ chạy ở trường hợp đầu.

__name__ thay đổi tùy theo cách file chạy
__name__(biến đặc biệtPython tự đặt)Chạy trực tiếppython xxx.py__name__= "__main__"Được file khácimport__name__= "xxx"(tên module)
Biến đặc biệt tự đặt __name__"__main__" khi bạn chạy trực tiếp (python xxx.py), và là tên module (tên file) khi file khác import nó.
# math_utility.py
def add(a, b):
    return a + b


# Smoke test chỉ khi chạy trực tiếp
if __name__ == "__main__":
    print("check:", add(10, 20))   # 30

# Khi file khác làm `import math_utility`,
# block if ở trên không chạy — chỉ hàm add được expose.

math_utility_2.py đính kèm định nghĩa hàm show_name() in ra __name__ của chính nó, cộng với một block if __name__ == "__main__": ở dưới cùng (mở từ 📂 Files để xem).

① Từ phía main, import math_utility_2 và in __name__ của main.

② Gọi math_utility_2.show_name() và xem __name__ từ phía được import trông như thế nào.

Python Editor

Chạy code để xem đầu ra

Kết hợp nhiều module của riêng bạn

Trong ứng dụng thật, bạn thường chia hàm vào các file riêng theo trách nhiệm rồi kéo tất cả vào từ main.py. Ví dụ, kiểm tra input nằm ở validator.py, định dạng hiển thị ở formatter.py. Khi trách nhiệm chia thế này, thay đổi định dạng chỉ động đến formatter.py — main.py và validator.py vẫn nguyên vẹn.

main.py kết hợp hai module của riêng bạn
main.pyimport validatorimport formattervalidator.pyis_valid_price()formatter.pyformat_price()importimport
main.py import hai module với import validatorimport formatter, rồi kết hợp các hàm của chúng để hoàn thành một việc.

Hoàn thiện validator.py và formatter.py đính kèm, rồi import cả hai từ main.py.

① Trong validator.py, triển khai is_valid_price(price) — trả về True nếu price là một int dương, False nếu khác.

② Trong formatter.py, triển khai format_price(price) — nhận một int, cộng phụ phí 5% với int(price + price * 0.05), và trả về một chuỗi như "with tax: $1575".

③ Trong main.py, import cả hai. Quyết định xem price = 1500 có hợp lệ không, định dạng nó, và in ra kết quả.

Python Editor

Chạy code để xem đầu ra

Bài này đã bao quát phân cấp module / package / library, cách import kéo hàm từ các file khác, cái gì chạy lúc import, mẫu __name__ == "__main__" để phân biệt chạy trực tiếp với import, và việc chia nhiều module trong đó mỗi file giữ một trách nhiệm. Bài tiếp theo đào sâu package và file __init__.py.

QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Cặp ánh xạ module / package / library nào là đúng?

Câu 2math_utility.py có print("hello") viết ở top level. Cái gì hiện ra màn hình khi file khác làm import math_utility?

Câu 3Cặp đúng cho chạy trực tiếp vs import của code này là gì?
if __name__ == "__main__":
print("hello")