Nhập từ một đường dẫn tương đối trong Python


104

Tôi có một thư mục cho mã khách hàng của mình, một thư mục cho mã máy chủ của tôi và một thư mục cho mã được chia sẻ giữa chúng

Proj/
    Client/
        Client.py
    Server/
        Server.py
    Common/
        __init__.py
        Common.py

Làm cách nào để nhập Common.py từ Server.py và Client.py?


Câu trả lời:


140

CHỈNH SỬA tháng 11 năm 2014 (3 năm sau):

Python 2.6 và 3.x hỗ trợ nhập tương đối thích hợp, nơi bạn có thể tránh làm bất cứ điều gì khó hiểu. Với phương pháp này, bạn biết rằng bạn đang nhận được một lần nhập tương đối chứ không phải là một lần nhập tuyệt đối . '..' có nghĩa là, chuyển đến thư mục phía trên tôi:

from ..Common import Common

Lưu ý, điều này sẽ chỉ hoạt động nếu bạn chạy python của mình dưới dạng mô-đun, từ bên ngoài gói. Ví dụ:

python -m Proj

Cách hacky ban đầu

Phương pháp này vẫn thường được sử dụng trong một số trường hợp, nơi bạn thực sự không bao giờ 'cài đặt' gói của mình. Ví dụ: nó phổ biến với người dùng Django.

Bạn có thể thêm Common / vào sys.path của mình (danh sách các đường dẫn mà python nhìn vào để nhập mọi thứ):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) chỉ cung cấp cho bạn thư mục chứa tệp python hiện tại của bạn và sau đó chúng tôi điều hướng đến thư mục 'Common /' và nhập mô-đun 'Common'.


2
Không sửa đổi đường dẫn mô-đun python theo cách thủ công, có thể chỉ dành cho các bản hack nhanh. Học quản lý gói Python bằng cách sử dụng distutils, setuptools, v.v. thường là một kỹ năng bắt buộc sẽ giải quyết các vấn đề như vậy.
Sascha Gottfried

1
@SaschaGottfried hoàn toàn đồng ý, mặc dù nếu bạn không tạo gói có thể phân phối, thì có lẽ sẽ không thành vấn đề. Ví dụ: trong Django, bạn không bao giờ thực sự cài đặt ứng dụng của mình bằng các bản phân phối, vì vậy phương pháp trên là một cách hack dễ dàng. Nhưng dù sao thì tôi đã chỉnh sửa câu trả lời với những gì tôi sẽ làm trong những ngày này.
Dave

32
Cảm ơn bạn đã trả lời câu hỏi thực tế thay vì rao giảng về kỹ thuật thích hợp. Có rất nhiều lý do chính đáng để thực hiện nhập khẩu tương đối.
shrewmouse

làm thế nào bạn sẽ lên nhiều hơn một cấp độ?
jxramos

10
để lên thêm một cấp, hãy sử dụng thêm một dấu chấm cho mỗi cấp. @jxramos ex: from ...myfileđi tới../../myfile
WattsInABox 21/08/18

10

Thật buồn cười, một vấn đề tương tự mà tôi vừa gặp, và tôi giải quyết công việc này theo cách sau:

kết hợp với lệnh linux ln, chúng ta có thể làm cho mọi thứ trở nên đơn giản hơn rất nhiều:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

Và, bây giờ nếu bạn muốn nhập some_stufftừ tệp: Proj/Common/Common.pyvào tệp của mình:, Proj/Client/Client.pygiống như sau:

# in Proj/Client/Client.py
from Common.Common import some_stuff

Và, điều tương tự cũng áp dụng cho Proj/Server, Cũng hoạt động cho setup.pyquá trình, một câu hỏi tương tự được thảo luận ở đây , hy vọng nó sẽ hữu ích!


10

Đừng nhập tương đối.

Từ PEP8 :

Nhập khẩu tương đối để nhập khẩu trong gói rất không được khuyến khích.

Đặt tất cả mã của bạn vào một siêu gói (tức là "myapp") và sử dụng các gói con cho máy khách, máy chủ và mã chung.

Cập nhật: " Python 2.6 và 3.x hỗ trợ nhập tương đối thích hợp (...) ". Xem câu trả lời của Dave để biết thêm chi tiết.


1
Hãy tưởng tượng rằng bạn thêm một số mã vào cuối máy khách và máy chủ sau dòng ' if __name__ == "__main__":'. Có nghĩa là, bạn muốn có thể sử dụng chúng như các tập lệnh độc lập. Làm thế nào để làm điều đó đúng? Tôi nghĩ rằng đó là một trường hợp sử dụng hoàn toàn phổ biến cần được hỗ trợ. Tại sao nó lại nản?
Jabba

83
Tôi ngạc nhiên rằng "Không làm điều đó" là câu trả lời được chấp nhận cho câu hỏi "làm thế nào để tôi ..." (tốt, ngoại trừ Rails <g>.) Đôi khi những lý do để làm điều này. Tôi sử dụng một giải pháp tương tự như những gì Dave gợi ý.
Tom Wilson

1
@TomWilson: Câu trả lời "không làm điều đó" không thuần túy. Có "làm theo cách này" bên dưới.
Michał Šrajer

2
Ai đó nên nói với những người ở Numpy! Họ sử dụng một TẤN hàng nhập khẩu tương đối!
Austin A

12
Câu trả lời này không áp dụng cho các phiên bản Python hiện tại. Phần được trích dẫn không còn được tìm thấy trong PEP 8. Ngày nay, nó có nội dung như: "Nhập khẩu tương đối rõ ràng là một sự thay thế có thể chấp nhận được cho nhập khẩu tuyệt đối, đặc biệt khi xử lý các bố cục gói phức tạp trong đó sử dụng nhập khẩu tuyệt đối sẽ dài dòng một cách không cần thiết"
moooeeeep

8

Thực hiện nhập khẩu tương đối là hoàn toàn OK! Đây là những gì tôi làm:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py

1
Nhưng bạn nên biết rõ hơn nơi sys.argv [0] đang thực sự trỏ đến - nó (prolly) không phải là thư mục bạn đã ở khi bắt đầu python.
CarlH

Đây là một cách hack nhanh chóng, với rất nhiều cạm bẫy. Nhưng câu hỏi thậm chí còn không tốt hơn.
Sascha Gottfried

1
Đây được viết rõ ràng, nhưng hack gốc trong câu trả lời của Dave là tốt hơn vì nó sử dụng __file__để có được những mối quan hệ đúng đắn từ tập tin hiện tại
John Neuhaus

4

Phương thức nhập mặc định đã là "tương đối", từ PYTHONPATH. Theo mặc định, PYTHONPATH cho một số thư viện hệ thống cùng với thư mục của tệp nguồn gốc. Nếu bạn chạy với -m để chạy một mô-đun, thư mục hiện tại sẽ được thêm vào PYTHONPATH. Vì vậy, nếu điểm vào chương trình của bạn nằm bên trong Proj, thì việc sử dụng import Common.Commonsẽ hoạt động bên trong cả Server.py và Client.py.

Đừng nhập tương đối. Nó sẽ không hoạt động theo cách bạn muốn.


1
Nếu điều này là đúng, tại sao các câu trả lời hàng đầu không nói điều này? Điều này sẽ hoạt động hay không?
Anonymous
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.