Python Arama Yolunu Diğer Kaynağa Genişlet


107

Oldukça büyük bir mevcut kod tabanına sahip bir projeye yeni katıldım. Linux'ta geliştiriyoruz ve IDE kullanmıyoruz. Komut satırından geçiyoruz. Proje modüllerini çalıştırdığımda python'un doğru yolu aramasını nasıl sağlayacağımı anlamaya çalışıyorum. Örneğin, şöyle bir şey çalıştırdığımda:

python someprojectfile.py

alırım

ImportError: no module named core.'somemodule'

Bunu tüm ithalatlarım için alıyorum, bunun yolla ilgili bir sorun olduğunu varsayıyorum.

TLDR:

Python'un ~/codez/project/içe aktarma ifadeleri sırasında * .py dosyaları için arama yapmasını ve tüm dosya ve klasörleri nasıl elde edebilirim ?

Yanıtlar:


172

Bunu yapmanın birkaç olası yolu vardır:

  • Ortam değişkenini PYTHONPATH, içe aktarılan modülleri aramak için iki nokta üst üste işaretiyle ayrılmış dizinler listesine ayarlayın .
  • Programınızda, sys.path.append('/path/to/search')Python'un içe aktarılan modülleri aramasını istediğiniz dizinlerin adlarını eklemek için kullanın . sys.pathsadece Python'un bir modülü içe aktarması istendiğinde aradığı dizinlerin listesidir ve gerektiğinde değiştirebilirsiniz (standart dizinlerden herhangi birinin kaldırılmasını önermememe rağmen!). Ortam değişkenine koyduğunuz tüm dizinler Python başladığında PYTHONPATHiçine eklenecektir sys.path.
  • Kullanım site.addsitediriçin bir dizin eklemek için sys.path. Bununla sadece düz ekleme arasındaki fark, kullandığınızda addsitedir, o .pthdizindeki dosyaları da araması ve dosyaların sys.pathiçeriğine bağlı olarak muhtemelen ek dizinler eklemek için bunları kullanmasıdır . Daha fazla ayrıntı için belgelere bakın.

Bunlardan hangisini kullanmak istediğiniz, durumunuza bağlıdır. Projenizi diğer kullanıcılara dağıtırken, genellikle onu Python kod dosyalarının Python'un ithalatçısı tarafından otomatik olarak algılanacak şekilde kurduklarını unutmayın (yani paketler genellikle site-packagesdizine kurulur ), bu nedenle sys.pathkodunuzla uğraşırsanız , bu gereksiz olabilir ve hatta bu kod başka bir bilgisayarda çalıştığında olumsuz etkileri olabilir. Geliştirme için, ortamın PYTHONPATHgenellikle gitmek için en iyi yol olduğunu tahmin etmeye cesaret ediyorum .

Bununla birlikte, yalnızca kendi bilgisayarınızda çalışan bir şey kullandığınızda (veya standart olmayan kurulumlarınız olduğunda, örneğin bazen web uygulaması çerçevelerinde), böyle bir şey yapmak tamamen alışılmadık bir şey değildir.

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

Yani 15 alt dizini söylemek isteseydim, her birini ayrı ayrı eklemem gerekirdi?
themaestro

ve PYTHONPATH'ı değiştirmek için bir komut satırı argümanı örneği verebilir misiniz?
themaestro

3
Ayarlamak için PYTHONPATH: içinde .bashrcveya kabuğunuzun kullandığı başlangıç ​​dosyasında (Bash değilse) yazın export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Ama bir sürü alt dizininiz varsa, bir .pthdosya oluşturup kullanırdım site.addsitedir. sitecustomizeİşlevi sizin için çağırabilecek bir modül oluşturabilirsiniz ; ~/.local/lib/python2.6/sitecustomize.pyyerine koymayı deneyin (Python sürümünüzü değiştirin), böylece otomatik olarak içe aktarılır.
David Z

Aşağıdakileri .bashrc dosyama ekledim ve bu içe aktarma işlemlerinde hala şansım yok. Herhangi bir fikir? Yine de bir .pth dosyasını nasıl yaparım? dışa aktar PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / dışa aktar PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / proje dışa aktarımı PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / proje / çekirdek ihracat PYTHONPAT $ ANA SAYFA / adaifotis / codez / proje / proxy dışa aktarım PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / conf
themaestro

Bir terminal açıp çalıştırmayı deneyin echo $PYTHONPATH. Ortam değişkeni doğru bir şekilde ayarlanmışsa, iki nokta üst üste işaretiyle ayrılmış bir dizin listesi görmelisiniz. .pthDosyalar hakkında bilgi için, sitecevabımda bağlantı verdiğim modülün belgelerine bakın . İçeriğin ne olması gerektiğini ve nasıl kullanılacağını size söyler.
David Z

13

Ayrıca burada python paketleri hakkında bilgi almalısınız: http://docs.python.org/tutorial/modules.html .

Örneğinizden, gerçekten bir paketiniz olduğunu tahmin ediyorum ~/codez/project. __init__.pyBir python dizinindeki dosya , bir dizini bir ad alanına eşler. Alt dizinlerinizin hepsinde bir __init__.pydosya varsa, yalnızca temel dizini PYTHONPATH. Örneğin:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / proje

PYTHONPATH ortam değişkeninizi test etmenin yanı sıra, David'in açıkladığı gibi, aşağıdaki gibi python'da test edebilirsiniz:

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

...


Bunun tersine, __init__.pygerçekten kastettiğinizi netleştirmek için geri işaretlerinizi koymak isteyebilirsiniz . Sadece yeni başlayanların kafasını karıştırmamak için. :)__init__.pyinit.py
antred

4

Bu konunun biraz eski olduğunu biliyorum, ama bunun özüne inmem biraz zaman aldı, bu yüzden paylaşmak istedim.

Projemde, ana betiği bir üst dizinde tuttum ve modülleri farklılaştırmak için tüm destekleyici modülleri "modüller" adı verilen bir alt klasöre koydum. Ana komut dosyamda, bu modülleri şu şekilde içe aktarıyorum (report.py adlı bir modül için):

from modules.report import report, reportError

Ana senaryomu ararsam, bu işe yarar. ANCAK, her bir modülü her birine bir ekleyerek main()ve her birini şu şekilde doğrudan arayarak test etmek istedim :

python modules/report.py

Şimdi Python, "modül adı verilen bir modül" bulamadığından şikayet ediyor. Buradaki anahtar, varsayılan olarak, Python'un komut dosyasının klasörünü arama yolunda içermesidir, ANCAK CWD DEĞİL. Öyleyse, bu hatanın söylediği şey, gerçekten, "Bir modül alt klasörü bulamıyorum". Bunun nedeni, report.py modülünün bulunduğu dizinde "modüller" alt dizini bulunmamasıdır.

Bunun en iyi çözümünün, CWD'yi Python arama yoluna eklemek olduğunu, bunu en üste ekleyerek buluyorum:

import sys

sys.path.append(".")

Python şimdi CWD'yi (mevcut dizin) arar, "modüller" alt klasörünü bulur ve her şey yolunda.


3

Bu soruyu cevap ararken okudum ve hiçbirini beğenmedim.

Bu yüzden hızlı ve kirli bir çözüm yazdım. Bunu sys.path'inizde bir yere koyun ve herhangi bir dizini altına folder(mevcut çalışma dizininden) veya altına ekler 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
]

Ve hoşuma gitti çünkü bazı rasgele araçlar için bir klasöre sahip olabilirim ve bunların paketlerin bir parçası ya da herhangi bir şeyin parçası olmamasına rağmen, bazılarına (veya tümüne) birkaç satır kodla erişebilirim.


3

Bulduğum en kolay yol, bir "herhangi_adı.pth" dosyası oluşturmak ve onu "\ Lib \ site-packages" klasörünüze koymaktır. Python'un kurulu olduğu her yerde bu klasörü bulmalısınız.

Bu dosyaya, modüllerin içe aktarılması için saklamak istediğiniz dizinlerin bir listesini koyun. Örneğin, bu dosyada şu şekilde bir satır yapın:

C: \ Kullanıcılar \ örnek ... \ örnek

Bunu python'da çalıştırarak çalıştığını söyleyebileceksiniz:

import sys
for line in sys: print line

Diğerlerinin yanı sıra içeri aktarabileceğiniz dizininizin çıktısını göreceksiniz. Artık bu dizinde bulunan bir "mymodule.py" dosyasını şu şekilde kolayca içe aktarabilirsiniz:

import mymodule

Bu, alt klasörleri içe aktarmayacaktır. Bunun için, tanımladığınız bir klasörün tüm alt klasörlerini içeren bir .pth dosyası oluşturmak için bir python betiği oluşturmayı hayal edebilirsiniz. Belki başlangıçta çalışmasını sağlayın.


0

Eski soru için yeni seçenek.
Yükleme fail2banDebian paketi, böyle görünüyor yüklemek hardcoded /usr/lib/python3/dist-packages/fail2banbir yol değil python3 üzerinde 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']
>>>

bu yüzden, sadece kopyalamak yerine, kitaplığı yeni sürümlere bağladım (bash).
Orijinal uygulamaya gelecek güncellemeler de bağlantılı sürümlere otomatik olarak uygulanacaktır.

 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.