Python: nhập mô-đun từ một thư mục khác ở cùng cấp trong hệ thống phân cấp dự án


87

Tôi đã xem tất cả các loại ví dụ và các câu hỏi tương tự khác, nhưng dường như tôi không thể tìm thấy một ví dụ nào phù hợp chính xác với kịch bản của tôi. Tôi cảm thấy mình giống như một kẻ ngu ngốc hỏi điều này vì có rất nhiều câu hỏi tương tự, nhưng tôi dường như không thể làm cho câu hỏi này hoạt động "chính xác". Đây là dự án của tôi:

user_management  (package)
        |
        |------- __init__.py
        |
        |------- Modules/
        |           |
        |           |----- __init__.py
        |           |----- LDAPManager.py
        |           |----- PasswordManager.py
        |
        |------- Scripts/
        |           |
        |           |----- __init__.py
        |           |----- CreateUser.py
        |           |----- FindUser.py

Nếu tôi chuyển "CreateUser.py" vào thư mục user_management chính, tôi có thể dễ dàng sử dụng: "import Modules.LDAPManager"để nhập LDAPManager.py --- điều này hoạt động. Điều tôi không thể làm (điều tôi muốn làm) là giữ CreateUser.py trong thư mục con Scripts và nhập LDAPManager.py. Tôi đã hy vọng đạt được điều này bằng cách sử dụng "import user_management.Modules.LDAPManager.py". Điều này không hoạt động. Tóm lại, tôi có thể lấy các tệp Python để dễ dàng tìm hiểu sâu hơn trong hệ thống phân cấp, nhưng tôi không thể lấy một tập lệnh Python để tham chiếu lên một thư mục này và xuống một thư mục khác.

Lưu ý rằng tôi có thể giải quyết vấn đề của mình bằng cách sử dụng:

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import Modules.LDAPManager as LDAPManager

Tôi nghe nói rằng đây là một thực hành xấu và không khuyến khích.

Các tệp trong Scripts nhằm mục đích được thực thi trực tiếp ( init .py trong Scripts có cần thiết không?). Tôi đã đọc rằng trong trường hợp này, tôi nên thực thi CreateUser.py với cờ -m. Tôi đã thử một số biến thể về điều này và dường như không thể khiến CreateUser.py nhận ra LDAPManager.py.

Câu trả lời:


66

Nếu tôi chuyển CreateUser.pyđến thư mục user_management chính, tôi có thể dễ dàng sử dụng: import Modules.LDAPManagerto import LDAPManager.py --- điều này hoạt động.

Làm ơn, đừng . Theo cách này, LDAPManagermô-đun được sử dụng CreateUsersẽ không giống với mô-đun được nhập qua các lần nhập khác. Điều này có thể tạo ra sự cố khi bạn có một số trạng thái chung trong mô-đun hoặc trong quá trình chọn / giải nén. Tránh nhập chỉ hoạt động vì mô-đun tình cờ nằm ​​trong cùng một thư mục.

Khi bạn có cấu trúc gói, bạn nên:

  • Sử dụng nhập khẩu tương đối, tức là nếu CreateUser.pytrong Scripts/:

     from ..Modules import LDAPManager
    

    Lưu ý rằng đây (lưu ý sự qua căng thẳng) nản chí bởi PEP 8 chỉ vì các phiên bản cũ của python không hỗ trợ họ rất tốt, nhưng vấn đề này đã được giải quyết năm trước. Các hiện phiên bản của PEP 8 không đề nghị chúng như một sự thay thế chấp nhận được để nhập khẩu tuyệt đối. Tôi thực sự thích chúng bên trong các gói.

  • Sử dụng nhập khẩu tuyệt đối bằng cách sử dụng toàn bộ tên gói ( CreateUser.pytrong Scripts/):

     from user_management.Modules import LDAPManager
    

Để cái thứ hai hoạt động, gói user_managementphải được cài đặt bên trong PYTHONPATH. Trong quá trình phát triển, bạn có thể định cấu hình IDE để điều này xảy ra mà không cần phải thêm các cuộc gọi đến sys.path.appendbất kỳ đâu theo cách thủ công .

Ngoài ra, tôi thấy thật kỳ lạ khi đó Scripts/là một gói con. Bởi vì trong cài đặt thực, user_managementmô-đun sẽ được cài đặt trong thư mục site-packagestìm thấy trong lib/thư mục (bất kỳ thư mục nào được sử dụng để cài đặt thư viện trong hệ điều hành của bạn), trong khi các tập lệnh phải được cài đặt trong một bin/thư mục (thư mục nào chứa tệp thực thi cho hệ điều hành của bạn).

Trong thực tế, tôi tin rằng Script/thậm chí không nên ở dưới user_management. Nó phải ở cùng mức độ user_management. Theo cách này, bạn không cần phải sử dụng -mmà chỉ cần đảm bảo rằng gói có thể được tìm thấy (đây một lần nữa là vấn đề cấu hình IDE, cài đặt gói chính xác hoặc sử dụng PYTHONPATH=. python Scripts/CreateUser.pyđể khởi chạy các tập lệnh với đường dẫn chính xác).


Tóm lại, hệ thống phân cấp tôi sẽ sử dụng là:

user_management  (package)
        |
        |------- __init__.py
        |
        |------- Modules/
        |           |
        |           |----- __init__.py
        |           |----- LDAPManager.py
        |           |----- PasswordManager.py
        |

 Scripts/  (*not* a package)
        |  
        |----- CreateUser.py
        |----- FindUser.py

Sau đó, mã của CreateUser.pyFindUser.pynên sử dụng nhập khẩu tuyệt đối để nhập các mô-đun:

from user_management.Modules import LDAPManager

Trong khi cài đặt, bạn đảm bảo rằng nó user_managementkết thúc ở đâu đó trong PYTHONPATHvà các tập lệnh bên trong thư mục cho các tệp thực thi để chúng có thể tìm thấy các mô-đun. Trong quá trình phát triển, bạn dựa vào cấu hình IDE hoặc bạn khởi chạy CreateUser.pythêm Scripts/thư mục mẹ vào PYTHONPATH(ý tôi là thư mục chứa cả user_managementScripts):

PYTHONPATH=/the/parent/directory python Scripts/CreateUser.py

Hoặc bạn có thể sửa đổi PYTHONPATHtoàn cục để không phải chỉ định điều này mỗi lần. Trên hệ điều hành unix (linux, Mac OS X, v.v.), bạn có thể sửa đổi một trong các tập lệnh shell để xác định PYTHONPATHbiến bên ngoài, trên Windows, bạn phải thay đổi cài đặt biến môi trường.


Phụ lục Tôi tin rằng, nếu bạn đang sử dụng python2, tốt hơn nên đảm bảo tránh nhập tương đối ngầm bằng cách đặt:

from __future__ import absolute_import

ở đầu mô-đun của bạn. Theo cách này, import X luôn luôn có nghĩa là nhập mô-đun cấp cao nhấtX và sẽ không bao giờ cố gắng nhập X.pytệp trong cùng một thư mục (nếu thư mục đó không có trong PYTHONPATH). Theo cách này, cách duy nhất để thực hiện nhập tương đối là sử dụng cú pháp rõ ràng (the from . import X), cú pháp này tốt hơn ( rõ ràng tốt hơn là ẩn ).

Điều này sẽ đảm bảo rằng bạn không bao giờ tình cờ sử dụng các phép nhập tương đối ngầm "không có thật", vì chúng sẽ ImportErrorbáo hiệu rõ ràng rằng có điều gì đó không ổn. Nếu không, bạn có thể sử dụng một mô-đun không giống như bạn nghĩ.


Nếu bạn đang sử dụng nhập khẩu tương đối, bạn nên thực hiệnpython -m user_management.Scripts.CreateUser
Mononoke

14

Từ Python 2.5 trở đi, bạn có thể sử dụng

from ..Modules import LDAPManager

Giai đoạn dẫn đầu đưa bạn "lên" một cấp độ trong hệ thống của mình.

Xem tài liệu Python về các tham chiếu trong gói để nhập.


3

Trong "root", __init__.pybạn cũng có thể làm

import sys
sys.path.insert(1, '.')

điều này sẽ làm cho cả hai mô-đun có thể nhập được.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.