Python: import mô-đun bằng đường dẫn tương đối (kèm sửa lỗi)

1. Tổng quan về câu lệnh import và import theo đường dẫn tương đối trong Python

Khi viết chương trình bằng Python, bạn sử dụng câu lệnh import để tái sử dụng mô-đun một cách hiệu quả. Trong câu lệnh import này, import theo đường dẫn tương đối đặc biệt hữu ích khi bạn cần các quan hệ phụ thuộc linh hoạt giữa các mô-đun. Bài viết này sẽ giải thích cách dùng đường dẫn tương đối trong câu lệnh import của Python và những lợi ích của nó。

Import theo đường dẫn tương đối là gì?

Import theo đường dẫn tương đối là cách import mô-đun khác dựa trên vị trí của mô-đun hiện tại. Điều này đặc biệt hữu ích trong các dự án lớn hoặc khi phát triển package có nhiều mô-đun. Bằng cách dùng import theo đường dẫn tương đối, các quan hệ phụ thuộc giữa các mô-đun trở nên rõ ràng hơn và việc bảo trì dự án trở nên dễ dàng hơn。 Ví dụ, giả sử bạn có cấu trúc thư mục như sau。
project/
    ├── main.py
    ├── package/
    │   ├── module_a.py
    │   └── sub_package/
    │       └── module_b.py
Từ module_b.py, để import module_a.py theo đường dẫn tương đối, bạn viết như sau。
from ..module_a import some_function
Như vậy, với đường dẫn tương đối, bạn có thể import mô-đun một cách linh hoạt dựa trên cấu trúc phân cấp của thư mục。

2. Sự khác nhau giữa đường dẫn tương đối và tuyệt đối

Trong Python, câu lệnh import có hai kiểu: đường dẫn tương đối và đường dẫn tuyệt đối. Hai kiểu này khác nhau ở cách chỉ định mô-đun cần nhập.

Import bằng đường dẫn tuyệt đối

Import bằng đường dẫn tuyệt đối là cách chỉ định mô-đun cần nhập bắt đầu từ thư mục gốc của dự án. Chẳng hạn, với một dự án có cấu trúc như vậy, nếu nhập module_a.py từ main.py bằng đường dẫn tuyệt đối, bạn sẽ viết như sau.
from package.module_a import some_function
Cách này hữu ích khi cấu trúc toàn dự án rõ ràng và vị trí các mô-đun nhất quán.

Import bằng đường dẫn tương đối

Ngược lại, import bằng đường dẫn tương đối phụ thuộc vào vị trí của mô-đun hiện tại để nhập mô-đun khác. Import tương đối đặc biệt linh hoạt khi cấu trúc dự án thay đổi. Nhờ đó, bạn có thể duy trì các phụ thuộc giữa các mô-đun đồng thời nâng cao khả năng tái sử dụng mã. Ví dụ, đoạn mã dưới đây minh họa việc nhập một mô-đun nằm ở thư mục cha của mô-đun hiện tại.
from ..module_a import some_function
Việc chọn cách nào phụ thuộc vào quy mô và độ phức tạp của dự án; nói chung, nếu vị trí mô-đun cố định thì dùng đường dẫn tuyệt đối, còn nếu thay đổi thường xuyên thì đường dẫn tương đối sẽ phù hợp hơn.
侍エンジニア塾

3. Cách import bằng đường dẫn tương đối

Import mô-đun trong cùng thư mục

Khi import một mô-đun nằm trong cùng thư mục, bạn không cần chỉ định gì phức tạp; chỉ cần nêu tên mô-đun. Ví dụ, nếu module_a.pymodule_b.py nằm trong cùng một thư mục, bạn có thể import như sau。
import module_a
Ngoài ra, nếu muốn import một hàm hoặc lớp cụ thể thì làm như sau。
from module_a import some_function

Import từ thư mục cha

Khi import mô-đun nằm ở thư mục cấp trên, hãy dùng .. để quay về một cấp, rồi chỉ định mô-đun. Ví dụ, để import từ thư mục cao hơn một cấp, viết như sau。
from ..module_a import some_function

Import từ thư mục con

Khi import mô-đun từ thư mục con, hãy chỉ định tên thư mục và tên mô-đun, phân tách bằng dấu chấm. Ví dụ, import mô-đun trong thư mục con như sau。
from sub_package.module_b import some_function
Việc sử dụng đường dẫn tương đối có ưu điểm lớn là ngay cả khi cấu trúc thư mục trong dự án thay đổi, mã vẫn có thể thích ứng linh hoạt.

4. Nhập mô-đun trong gói

Trong Python có khái niệm “package” (gói) để tổ chức các mô-đun. Gói rất tiện khi xử lý nhiều mô-đun cùng lúc, đặc biệt hữu ích cho các dự án lớn. Bạn cũng có thể import các mô-đun trong gói bằng đường dẫn tương đối。

Cấu trúc của gói và tệp __init__.py

Khi tạo một gói, bạn cần thêm một tệp có tên __init__.py vào thư mục đó. Tệp này có vai trò giúp Python nhận diện thư mục đó là một “gói”. Chúng ta sẽ giải thích bằng ví dụ về một cấu trúc dự án như sau。
project/
    ├── main.py
    ├── package/
    │   ├── __init__.py
    │   ├── module_a.py
    │   └── sub_package/
    │       ├── __init__.py
    │       └── module_b.py

Import mô-đun trong gói bằng đường dẫn tương đối

Ví dụ, nếu import module_a.py từ module_b.py bằng đường dẫn tương đối, hãy viết như sau。
from ..module_a import some_function
Ký hiệu .. này có nghĩa là di chuyển lên một cấp so với thư mục hiện tại. Bằng cách này, bạn có thể chia sẻ các hàm và lớp giữa các mô-đun trong cùng gói。 Ngoài ra, khi import mô-đun trong cùng một gói bằng đường dẫn tương đối, bạn có thể dùng dấu chấm để chỉ định một cách đơn giản.
from .module_a import some_function
Nhờ vậy, các mô-đun trong dự án có thể liên kết với nhau gọn gàng, và ngay cả khi cấu trúc thư mục thay đổi, bạn không cần phải chỉnh sửa nhiều mã nguồn.
RUNTEQ(ランテック)|超実戦型エンジニア育成スクール

5. Các lỗi thường gặp và cách khắc phục

Trong việc import theo đường dẫn tương đối trong Python, có thể phát sinh một số lỗi điển hình. Phần này sẽ giải thích các lỗi đó và cách giải quyết.

ImportError: attempted relative import with no known parent package

Lỗi này là một lỗi thường gặp khi bạn cố gắng import mô-đun bằng đường dẫn tương đối. Đặc biệt xảy ra khi script được chạy trực tiếp. Ví dụ, đoạn mã sau có thể gây ra vấn đề.
from ..module_a import some_function
Lỗi này xảy ra vì Python không thể nhận diện được gói cha của script. Trong Python, cần phải xác định rõ rằng mô-đun thuộc về một gói. Khi chạy script trực tiếp, việc sử dụng đường dẫn tương đối rất dễ gây ra lỗi.

Cách khắc phục

Một cách để tránh vấn đề này là sử dụng sys.path để thiết lập rõ ràng đường dẫn tìm kiếm mô-đun. Chẳng hạn, dùng sys.path.append() như dưới đây để thêm thư mục cha vào đường dẫn tìm kiếm.
import sys
sys.path.append('..')
from module_a import some_function
Nhờ đó, Python có thể tìm thấy mô-đun một cách chính xác.

ModuleNotFoundError

Một lỗi thường gặp khác là ModuleNotFoundError. Lỗi này xảy ra khi không tìm thấy mô-đun được chỉ định. Khi cố gắng import mô-đun bằng đường dẫn tương đối, nguyên nhân có thể là vị trí mô-đun không đúng hoặc sys.path chưa được thiết lập đúng.

Cách khắc phục

Để giải quyết vấn đề này, hãy xem lại câu lệnh import và xác minh rằng mô-đun thực sự tồn tại. Ngoài ra, bạn có thể tránh lỗi bằng cách dùng sys.path.append() để chỉ định rõ thư mục mà Python có thể tìm thấy mô-đun.

6. Ví dụ thực tiễn và ứng dụng

Ở đây, chúng tôi giới thiệu các ví dụ mã cụ thể sử dụng import theo đường dẫn tương đối. Qua đó, bạn sẽ thấy cách tận dụng đường dẫn tương đối trong các dự án thực tế.

Ví dụ: Import từ thư mục cha

Giả sử bạn có cấu trúc dự án như sau.
project/
    ├── main.py
    ├── package/
    │   ├── module_a.py
    │   └── sub_package/
    │       └── module_b.py
Mã để import hàm some_function của module_a.py từ module_b.py như sau.
# module_b.py
from ..module_a import some_function

def use_function():
    some_function()
Trong đoạn mã này, sử dụng .. để quay lại một thư mục cấp trên và import hàm từ module_a. Cách này hữu ích khi chia sẻ hàm hoặc lớp giữa các mô-đun thuộc nhiều thư mục khác nhau.

Ví dụ: Import mô-đun bằng sys.path

Tiếp theo, minh họa ví dụ import mô-đun ở thư mục cha bằng sys.path.append().
# module_b.py
import sys
sys.path.append('..')
from module_a import some_function

def use_function():
    some_function()
Với cách này, vì bạn thêm thư mục cha vào sys.path, Python có thể tìm thấy module_a một cách chính xác. Cách tiếp cận này đặc biệt hiệu quả khi chạy trực tiếp tập lệnh.

7. Kết luận

Bài viết này đã trình bày chi tiết về việc import theo đường dẫn tương đối trong câu lệnh import của Python. Import theo đường dẫn tương đối cho phép quản lý linh hoạt các phụ thuộc giữa các mô-đun trong dự án, vì vậy đặc biệt hữu ích cho các dự án quy mô lớn và trong phát triển gói. Tuy nhiên, nó cũng dễ phát sinh lỗi, nên việc cấu hình phù hợp và sử dụng sys.path là rất quan trọng. Hiểu rõ các ưu điểm của import theo đường dẫn tương đối và vận dụng trong các dự án thực tế sẽ giúp việc quản lý mã nguồn trở nên hiệu quả hơn.
年収訴求