Perluas Jalur Pencarian Python ke Sumber Lain

106

Saya baru saja bergabung dengan sebuah proyek dengan basis kode yang cukup besar. Kami mengembangkan di linux dan tidak menggunakan dan IDE. Kami menjalankan melalui baris perintah. Saya mencoba mencari cara agar python mencari jalur yang benar ketika saya menjalankan modul proyek. Misalnya, ketika saya menjalankan sesuatu seperti:

python someprojectfile.py

saya mendapat

ImportError: no module named core.'somemodule'

Saya mendapatkan ini untuk semua impor saya karena saya menganggap ini masalah dengan jalurnya.

TLDR:

Bagaimana cara mendapatkan Python untuk mencari ~/codez/project/dan semua file dan folder untuk file * .py selama pernyataan impor.

themaestro
sumber

Jawaban:

171

Ada beberapa cara yang mungkin untuk melakukan ini:

  • Setel variabel lingkungan PYTHONPATHke daftar direktori yang dipisahkan oleh titik dua untuk mencari modul yang diimpor.
  • Dalam program Anda, gunakan sys.path.append('/path/to/search')untuk menambahkan nama direktori yang Anda inginkan agar Python mencari modul yang diimpor. sys.pathhanyalah daftar direktori yang dicari Python setiap kali diminta untuk mengimpor modul, dan Anda dapat mengubahnya sesuai kebutuhan (meskipun saya tidak akan merekomendasikan menghapus direktori standar!). Direktori apa pun yang Anda masukkan ke dalam variabel lingkungan PYTHONPATHakan dimasukkan sys.pathsaat Python dijalankan.
  • Gunakan site.addsitediruntuk menambahkan direktori ke sys.path. Perbedaan antara ini dan hanya menambahkan biasa adalah ketika Anda menggunakannya addsitedir, itu juga mencari .pthfile di dalam direktori itu dan menggunakannya untuk kemungkinan menambahkan direktori tambahan sys.pathberdasarkan konten file. Lihat dokumentasi untuk detail lebih lanjut.

Yang mana yang ingin Anda gunakan tergantung pada situasi Anda. Ingatlah bahwa ketika Anda mendistribusikan proyek Anda ke pengguna lain, mereka biasanya menginstalnya sedemikian rupa sehingga file kode Python akan secara otomatis terdeteksi oleh importir Python (yaitu paket biasanya dipasang di site-packagesdirektori), jadi jika Anda mengacaukan sys.pathkode Anda , yang mungkin tidak perlu dan bahkan mungkin memiliki efek buruk saat kode tersebut dijalankan di komputer lain. Untuk pengembangan, saya berani menebak bahwa pengaturan PYTHONPATHbiasanya merupakan cara terbaik untuk pergi.

Namun, ketika Anda menggunakan sesuatu yang hanya berjalan di komputer Anda sendiri (atau ketika Anda memiliki pengaturan yang tidak standar, misalnya kadang-kadang dalam kerangka aplikasi web), tidak jarang melakukan sesuatu seperti

import sys
from os.path import dirname
sys.path.append(dirname(__file__))
David Z
sumber
Jadi jika saya ingin mengatakan 15 subdirektori, saya harus menambahkan satu per satu?
themaestro
dan dapatkah Anda memberikan contoh argumen baris perintah untuk mengubah PYTHONPATH?
themaestro
3
Untuk menyetel PYTHONPATH: di .bashrcatau file startup apa pun yang digunakan shell Anda (jika bukan Bash), tulis export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Tetapi jika Anda memiliki banyak subdirektori, saya akan membuat .pthfile dan menggunakan site.addsitedir. Anda dapat membuat modul sitecustomizeyang dapat memanggil fungsi tersebut untuk Anda; coba letakkan di ~/.local/lib/python2.6/sitecustomize.py(gantikan versi Python Anda) sehingga mudah-mudahan diimpor secara otomatis.
David Z
Saya meletakkan yang berikut ini di file .bashrc saya dan saya masih tidak beruntung dengan impor tersebut. Ada ide? Bagaimana cara membuat file .pth? ekspor PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / ekspor PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / core export PYTHONPATH: $ BERANDA / adaifotis / codez / project / proxy ekspor PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / conf
themaestro
Coba buka terminal dan jalankan echo $PYTHONPATH. Jika variabel lingkungan telah disetel dengan benar, Anda akan melihat daftar direktori yang dipisahkan oleh titik dua. Untuk informasi tentang .pthfile, lihat dokumentasi untuk sitemodul yang saya tautkan dalam jawaban saya. Ini memberi tahu Anda apa isinya dan bagaimana menggunakannya.
David Z
13

Anda juga harus membaca tentang paket python di sini: http://docs.python.org/tutorial/modules.html .

Dari contoh Anda, saya kira Anda benar-benar memiliki paket di ~/codez/project. File __init__.pydalam direktori python memetakan direktori ke dalam namespace. Jika semua subdirektori Anda memiliki __init__.pyfile, Anda hanya perlu menambahkan direktori dasar ke file PYTHONPATH. Sebagai contoh:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / project

Selain menguji variabel lingkungan PYTHONPATH Anda, seperti yang dijelaskan David, Anda dapat mengujinya dengan python seperti ini:

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

...

Andrew B.
sumber
Anda mungkin ingin memasukkan __init__.pybackticks Anda untuk memperjelas maksud Anda __init__.py, bukan init.py. Hanya untuk menghindari pemula yang membingungkan. :)
semut
4

Saya tahu utas ini agak tua, tetapi perlu beberapa waktu untuk memahami inti permasalahan ini, jadi saya ingin berbagi.

Dalam proyek saya, saya memiliki skrip utama di direktori induk, dan, untuk membedakan modul, saya meletakkan semua modul pendukung dalam sub-folder yang disebut "modul". Dalam skrip utama saya, saya mengimpor modul ini seperti ini (untuk modul bernama report.py):

from modules.report import report, reportError

Jika saya memanggil skrip utama saya, ini berfungsi. NAMUN, saya ingin menguji setiap modul dengan memasukkan main()masing-masing, dan memanggil masing-masing secara langsung, sebagai:

python modules/report.py

Sekarang Python mengeluh bahwa ia tidak dapat menemukan "modul yang disebut modul". Kuncinya di sini adalah, secara default, Python menyertakan folder skrip di jalur pencariannya, TAPI BUKAN CWD. Jadi apa yang dikatakan kesalahan ini, sebenarnya, adalah "Saya tidak dapat menemukan subfolder modul". Ini karena tidak ada subdirektori "modul" dari direktori tempat modul report.py berada.

Saya menemukan bahwa solusi paling rapi untuk ini adalah menambahkan CWD dalam jalur pencarian Python dengan memasukkan ini di atas:

import sys

sys.path.append(".")

Sekarang Python mencari CWD (direktori saat ini), menemukan sub-folder "modul", dan semuanya baik-baik saja.

Tom Gordon
sumber
3

Saya membaca pertanyaan ini untuk mencari jawaban, dan tidak menyukai satupun dari mereka.

Jadi saya menulis solusi cepat dan kotor. Letakkan saja ini di suatu tempat di sys.path Anda, dan itu akan menambahkan direktori apa pun di bawah folder(dari direktori kerja saat ini), atau di bawah 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
]

Dan saya menyukainya karena saya dapat memiliki folder untuk beberapa alat acak dan tidak memilikinya menjadi bagian dari paket atau apa pun, dan masih mendapatkan akses ke beberapa (atau semua) di antaranya dalam beberapa baris kode.

Droogan
sumber
3

Cara termudah yang saya temukan adalah dengan membuat file "any_name.pth" dan meletakkannya di folder "\ Lib \ site-packages" Anda. Anda harus menemukan folder itu di mana pun python dipasang.

Di file itu, letakkan daftar direktori tempat Anda ingin menyimpan modul untuk diimpor. Misalnya, buat baris di file itu seperti ini:

C: \ Users \ example ... \ example

Anda akan dapat mengetahui bahwa ini berfungsi dengan menjalankan ini dengan python:

import sys
for line in sys: print line

Anda akan melihat direktori Anda dicetak, antara lain dari mana Anda juga dapat mengimpor. Sekarang Anda dapat mengimpor file "mymodule.py" yang ada di direktori itu semudah:

import mymodule

Ini tidak akan mengimpor subfolder. Untuk itu Anda bisa membayangkan membuat script python untuk membuat file .pth yang berisi semua sub folder dari folder yang Anda tentukan. Jalankan mungkin saat startup.

KieranPC
sumber
0

Opsi baru untuk pertanyaan lama.
Menginstal fail2banpaket di Debian, sepertinya itu di-hardcode untuk diinstal di /usr/lib/python3/dist-packages/fail2banjalur bukan di 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']
>>>

jadi, alih-alih hanya menyalin, saya (bash) menautkan pustaka ke versi yang lebih baru.
Pembaruan mendatang untuk aplikasi asli, juga akan diterapkan secara otomatis ke versi yang ditautkan.

 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
fcm
sumber