Mở rộng đường dẫn tìm kiếm Python sang nguồn khác


106

Tôi vừa tham gia một dự án với một cơ sở mã hiện có khá lớn. Chúng tôi phát triển trên linux và không sử dụng và IDE. Chúng tôi chạy qua dòng lệnh. Tôi đang cố gắng tìm ra cách để python tìm kiếm đúng đường khi tôi chạy mô-đun dự án. Ví dụ: khi tôi chạy một cái gì đó như:

python someprojectfile.py

tôi có

ImportError: no module named core.'somemodule'

Tôi nhận được điều này cho tất cả các lần nhập của mình và tôi cho rằng đó là vấn đề với đường dẫn.

TLDR:

Làm cách nào để lấy Python để tìm kiếm ~/codez/project/và tất cả các tệp và thư mục cho tệp * .py trong khi nhập các câu lệnh.

Câu trả lời:


171

Có một số cách khả thi để làm điều này:

  • Đặt biến môi trường PYTHONPATHthành danh sách thư mục được phân tách bằng dấu hai chấm để tìm kiếm các mô-đun đã nhập.
  • Trong chương trình của bạn, sử dụng sys.path.append('/path/to/search')để thêm tên của các thư mục mà bạn muốn Python tìm kiếm các mô-đun đã nhập. sys.pathchỉ là danh sách các thư mục mà Python tìm kiếm mỗi khi nó được yêu cầu nhập một mô-đun và bạn có thể thay đổi nó nếu cần (mặc dù tôi không khuyên bạn nên xóa bất kỳ thư mục tiêu chuẩn nào!). Bất kỳ thư mục nào bạn đặt trong biến môi trường PYTHONPATHsẽ được chèn vào sys.pathkhi Python khởi động.
  • Sử dụng site.addsitedirđể thêm một thư mục vào sys.path. Sự khác biệt giữa điều này và chỉ bổ sung đơn thuần là khi bạn sử dụng addsitedir, nó cũng tìm kiếm .pthcác tệp trong thư mục đó và sử dụng chúng để có thể thêm các thư mục bổ sung sys.pathdựa trên nội dung của tệp. Xem tài liệu để biết thêm chi tiết.

Bạn muốn sử dụng cái nào trong số này tùy thuộc vào tình hình của bạn. Hãy nhớ rằng khi bạn phân phối dự án của mình cho những người dùng khác, họ thường cài đặt nó theo cách mà các tệp mã Python sẽ được phát hiện tự động bởi trình nhập Python (tức là các gói thường được cài đặt trong site-packagesthư mục), vì vậy nếu bạn có lỗi sys.pathtrong mã của mình , điều đó có thể không cần thiết và thậm chí có thể có tác dụng phụ khi mã đó chạy trên máy tính khác. Để phát triển, tôi sẽ dự đoán rằng thiết lập PYTHONPATHthường là cách tốt nhất để thực hiện.

Tuy nhiên, khi bạn đang sử dụng một thứ gì đó chỉ chạy trên máy tính của riêng bạn (hoặc khi bạn có các thiết lập không chuẩn, chẳng hạn như đôi khi trong các khuôn khổ ứng dụng web), việc làm như

import sys
from os.path import dirname
sys.path.append(dirname(__file__))

Vì vậy, nếu tôi muốn nói 15 thư mục con, tôi sẽ phải thêm từng thư mục một?
themaestro

và bạn có thể cho một ví dụ về đối số dòng lệnh để thay đổi PYTHONPATH không?
themaestro

3
Để đặt PYTHONPATH: trong .bashrchoặc bất kỳ tệp khởi động nào mà trình bao của bạn sử dụng (nếu nó không phải là Bash), hãy ghi export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Nhưng nếu bạn có một loạt các thư mục con, tôi sẽ tạo một .pthtệp và sử dụng site.addsitedir. Bạn có thể tạo một mô-đun sitecustomizecó thể gọi hàm cho bạn; hãy thử đặt nó tại ~/.local/lib/python2.6/sitecustomize.py(thay thế phiên bản Python của bạn) để hy vọng nó được nhập tự động.
David Z

Tôi đã đặt nội dung sau vào tệp .bashrc của mình và tôi vẫn không gặp may với những lần nhập đó. Bất kỳ ý tưởng? Tôi vẫn tạo tệp .pth bằng cách nào? export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / xuất dự án PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / core export PYTHONPATH = $ PYTHONPATH HOME / adaifotis / codez / dự án / proxy xuất khẩu PYTHONPATH = $ PYTHONPATH: $ / adaifotis / codez / dự án HOME / conf
themaestro

Hãy thử mở một thiết bị đầu cuối và chạy echo $PYTHONPATH. Nếu biến môi trường đã được đặt đúng cách, bạn sẽ thấy danh sách thư mục được phân tách bằng dấu hai chấm. Để biết thông tin về .pthtệp, hãy xem tài liệu cho sitemô-đun mà tôi đã liên kết đến trong câu trả lời của mình. Nó cho bạn biết nội dung nên có và cách sử dụng chúng.
David Z

13

Bạn cũng nên đọc về các gói python tại đây: http://docs.python.org/tutorial/modules.html .

Từ ví dụ của bạn, tôi đoán rằng bạn thực sự có một gói hàng tại ~/codez/project. Tệp __init__.pytrong thư mục python ánh xạ một thư mục vào một không gian tên. Nếu tất cả các thư mục con của bạn đều có một __init__.pytệp, thì bạn chỉ cần thêm thư mục cơ sở vào của mình PYTHONPATH. Ví dụ:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / dự án

Ngoài việc kiểm tra biến môi trường PYTHONPATH của bạn, như David giải thích, bạn có thể kiểm tra nó trong python như sau:

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...


Bạn có thể muốn đặt __init__.pybackticks của mình để làm rõ rằng bạn thực sự muốn nói gì __init__.py, trái ngược với init.py. Chỉ để tránh nhầm lẫn cho người mới. :)
antred

4

Tôi biết chủ đề này hơi cũ, nhưng tôi đã mất một thời gian để hiểu được trọng tâm của vấn đề này, vì vậy tôi muốn chia sẻ.

Trong dự án của mình, tôi có tập lệnh chính trong thư mục mẹ, và để phân biệt các mô-đun, tôi đặt tất cả các mô-đun hỗ trợ vào một thư mục con có tên "mô-đun". Trong tập lệnh chính của mình, tôi nhập các mô-đun này như thế này (đối với mô-đun có tên là report.py):

from modules.report import report, reportError

Nếu tôi gọi là kịch bản chính của tôi, thì nó sẽ hiệu quả. TUY NHIÊN, tôi muốn kiểm tra từng mô-đun bằng cách bao gồm một main()trong mỗi mô-đun và gọi trực tiếp từng mô-đun như:

python modules/report.py

Bây giờ Python phàn nàn rằng nó không thể tìm thấy "một mô-đun được gọi là mô-đun". Chìa khóa ở đây là, theo mặc định, Python bao gồm thư mục của tập lệnh trong đường dẫn tìm kiếm của nó, NHƯNG KHÔNG PHẢI LÀ CWD. Vì vậy, những gì lỗi này nói, thực sự, là "Tôi không thể tìm thấy một thư mục con mô-đun". Lý do là vì không có thư mục con "mô-đun" nào từ thư mục chứa mô-đun report.py.

Tôi thấy rằng giải pháp gọn gàng nhất cho vấn đề này là thêm đường dẫn tìm kiếm CWD trong Python bằng cách bao gồm điều này ở đầu:

import sys

sys.path.append(".")

Bây giờ Python tìm kiếm CWD (thư mục hiện tại), tìm thư mục con "module" và tất cả đều ổn.


3

Tôi đọc câu hỏi này để tìm câu trả lời và không thích bất kỳ câu trả lời nào.

Vì vậy, tôi đã viết một giải pháp nhanh chóng và bẩn thỉu. Chỉ cần đặt cái này ở đâu đó trên sys.path của bạn và nó sẽ thêm bất kỳ thư mục nào dưới folder(từ thư mục làm việc hiện tại) hoặc bên dưới abspath:

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

Và tôi thích nó vì tôi có thể có một thư mục cho một số công cụ ngẫu nhiên và không đặt chúng là một phần của gói hoặc bất cứ thứ gì, và vẫn có quyền truy cập vào một số (hoặc tất cả) chúng trong một vài dòng mã.


3

Cách dễ nhất mà tôi tìm thấy là tạo một tệp "any_name.pth" và đặt nó vào thư mục "\ Lib \ site-pack" của bạn. Bạn sẽ tìm thấy thư mục đó ở bất kỳ nơi nào python được cài đặt.

Trong tệp đó, hãy đặt một danh sách các thư mục mà bạn muốn giữ các mô-đun để nhập. Ví dụ: tạo một dòng trong tệp đó như sau:

C: \ Users \ example ... \ example

Bạn sẽ có thể cho biết nó hoạt động bằng cách chạy điều này trong python:

import sys
for line in sys: print line

Bạn sẽ thấy thư mục của mình được in ra, trong số những thư mục khác từ nơi bạn cũng có thể nhập. Giờ đây, bạn có thể nhập tệp "mymodule.py" nằm trong thư mục đó một cách dễ dàng như:

import mymodule

Thao tác này sẽ không nhập các thư mục con. Đối với điều đó, bạn có thể tưởng tượng việc tạo một tập lệnh python để tạo tệp .pth chứa tất cả các thư mục con của một thư mục bạn xác định. Có lẽ để nó chạy khi khởi động.


0

Tùy chọn mới cho câu hỏi cũ.
Cài đặt fail2bangói trên Debian, có vẻ như nó được mã hóa cứng để cài đặt trên /usr/lib/python3/dist-packages/fail2banđường dẫn không có trên python3 sys.path.


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

vì vậy, thay vì chỉ sao chép, tôi (bash) đã liên kết thư viện với các phiên bản mới hơn.
Các bản cập nhật trong tương lai cho ứng dụng gốc, cũng sẽ tự động được áp dụng cho các phiên bản được liên kết.

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
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.