Đây là cấu trúc thư mục của tôi:Làm thế nào để cấu trúc dự án Python của tôi để cho phép các module tên được nhập khẩu từ các thư mục phụ
Projects
+ Project_1
+ Project_2
- Project_3
- Lib1
__init__.py # empty
moduleA.py
- Tests
__init__.py # empty
foo_tests.py
bar_tests.py
setpath.py
__init__.py # empty
foo.py
bar.py
Mục tiêu:
- Có một cấu trúc dự án có tổ chức
- Hãy có thể chạy độc lập từng tệp .py khi cần thiết
- Có thể tham chiếu/nhập cả hai anh chị em và anh em họ mô-đun
- Giữ tất cả các lệnh nhập/từ ở đầu mỗi tệp.
tôi đã đạt đượC# 1 bằng cách sử dụng cấu trúc trên
Tôi đã chủ yếu đạt được 2, 3 và 4 bằng cách làm như sau (theo khuyến cáo của this excellent guide)
Trong bất kỳ gói mà cần phải truy cập cha mẹ hoặc anh em họ module (ví dụ như thư mục thử nghiệm ở trên) tôi bao gồm một tập tin gọi là setpath.py trong đó có đoạn mã sau:
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('...'))
sau đó, trong mỗi module mà cần truy cập phụ huynh/anh em họ, như foo_tests.py, tôi có thể viết một danh sách sạch đẹp hàng nhập khẩu như sau:
import setpath # Annoyingly, PyCharm warns me that this is an unused import statement
import foo.py
Bên setpath.py, chèn thứ hai và thứ ba là không thực sự cần thiết cho ví dụ này, nhưng được đưa vào như một bước xử lý sự cố .
Vấn đề của tôi là thao tác này chỉ hoạt động đối với các lần nhập trực tiếp tham chiếu tên mô-đun và không áp dụng cho các mục nhập tham chiếu đến gói. Ví dụ: bên trong bar_tests.py, cả hai câu lệnh bên dưới đều không hoạt động khi chạy bar_tests.py trực tiếp.
import setpath
import Project_3.foo.py # Error
from Project_3 import foo # Error
Tôi nhận được lỗi "ImportError: No module named 'Project_3'".
Điều kỳ lạ là tôi có thể chạy tệp trực tiếp từ bên trong PyCharm và nó hoạt động tốt. Tôi biết rằng PyCharm đang thực hiện một số phép thuật đằng sau hậu trường với biến số Python Path
để làm mọi thứ hoạt động, nhưng tôi không thể hiểu được nó là gì. Khi PyCharm đơn giản chạy python.exe và thiết lập một số biến môi trường, có thể sao chép hành vi này từ bên trong một tập lệnh Python.
Vì lý do không thực sự nảy mầm đối với câu hỏi này, tôi phải tham chiếu bar
bằng cách sử dụng vòng loại Project_3
.
Tôi đang mở cho bất kỳ giải pháp nào hoàn thành các giải pháp nêu trên trong khi vẫn đáp ứng các mục tiêu trước đó của tôi. Tôi cũng mở một cấu trúc thư mục thay thế nếu có một cấu trúc hoạt động tốt hơn. Tôi đã đọc số Python doc on imports và các gói nhưng vẫn bị mất. Tôi nghĩ rằng một đại lộ có thể có thể được đặt theo cách thủ công biến số __path__
, nhưng tôi không chắc chắn một biến nào cần được thay đổi hoặc những gì cần thiết để thay đổi.
Mặc dù tôi hoàn toàn đồng ý với câu trả lời @Blckknght (và trước khi anh ấy xuất bản, thậm chí bắt đầu viết tương tự trong cùng một giai điệu). Nó có thể đáng nói đến, trừ khi đó là một lỗi đánh máy khác, mô hình hiện tại của bạn có thể không hoạt động do sys.path.insert (0, os.path.abspath ('...')), như '...' không phải là một bộ chọn đường dẫn gốc hợp lệ. Ở đây bạn nên sử dụng ký hiệu hệ thống tập tin '../ ..' thông thường không phải là mô-đun cha của Python. – RobertT
@RobertT Không thể tin được!Vì vậy, đơn giản, nhưng nó sửa chữa vấn đề và có vẻ như là điều này cho phép tôi thiết lập rễ tương đối cho cả hai gói và mô-đun. Tôi vẫn nghĩ rằng một cái gì đó mạnh mẽ hơn có thể được thực hiện bằng cách sử dụng các thư viện nhập khẩu, nhưng điều này không trả lời questio của tôi, đạt được các mục tiêu trên. Làm cho nó một câu trả lời xin vui lòng và tôi sẽ xem xét nó cho giải thưởng tiền thưởng. – BrianHVB