Python: Mevcut çalışan betiğe göre sys.path'e eklemenin en iyi yolu


105

Komut dosyalarıyla dolu bir dizinim var (diyelim project/bin). Ayrıca içinde bir kitaplığım var project/libve komut dosyalarının onu otomatik olarak yüklemesini istiyorum. Normalde her betiğin üstünde kullandığım şey bu:

#!/usr/bin/python
from os.path import dirname, realpath, sep, pardir
import sys
sys.path.append(dirname(realpath(__file__)) + sep + pardir + sep + "lib")

# ... now the real code
import mylib

Bu biraz külfetli, çirkin ve her dosyanın başına yapıştırılması gerekiyor. Bunu yapmanın daha iyi bir yolu var mı?

Gerçekten umduğum şey şu kadar pürüzsüz:

#!/usr/bin/python
import sys.path
from os.path import pardir, sep
sys.path.append_relative(pardir + sep + "lib")

import mylib

Ya da daha da iyisi, editörüm (veya erişim yetkisi olan başka biri) temizleme sürecinin bir parçası olarak ithalatı yeniden düzenlemeye karar verdiğinde bozulmayacak bir şey:

#!/usr/bin/python --relpath_append ../lib
import mylib

Bu, doğrudan posix olmayan platformlara bağlanmaz, ancak işleri temiz tutar.


Yanıtlar:


25

Her dosyayı düzenlemek istemiyorsanız

  • Kitaplığınızı normal bir python kitaplığı gibi yükleyin
    veya
  • PYTHONPATHSenin için ayarlalib

veya her dosyaya tek bir satır eklemeye istekli iseniz, üst kısımda bir import ifadesi ekleyin, örn.

import import_my_lib

import_my_lib.pyçöp kutusunda tutun ve import_my_libpython yolunu libistediğiniz gibi doğru bir şekilde ayarlayabilir


122

Kullandığım şey bu:

import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), "lib"))

3
Diğer yollar tarafından geçersiz kılınmaması için sys.path.insert (0, ..) yapardım.
John Jiang

Bunun otomatik olarak çalışmasını sağlamanın gerçekten bir yolu yok mu?
Denis de Bernardy

1
Bu biraz riskli. Eğer __file__geçerli çalışma dizinine göreli bir dosya adı görecelidir (örneğin setup.py), sonra os.path.dirname(__file__)olacaktır boş dize. Bu ve For John Jiang tarafından gündeme benzer kaygılar , ekhumoro 's daha genel amaçlı çözüm kuvvetle tercih edilir.
Cecil Curry

30

Kullanıyorum:

import sys,os
sys.path.append(os.getcwd())

5
Sık sık yapıyorumsys.path.append('.')
kimbo

2
ya komut dosyası farklı bir dizinden çalıştırılırsa? örneğin kök dizinden tam sistem yolunu vererek? sonra os.getcwd () "/" döndürür
obayhan

2
Bunu asla yapmayın. Mevcut çalışma dizininin (CWD) düşündüğünüz gibi olduğu garanti edilmez - özellikle öngörülemeyen uç durumlarda kesinlikle bir mil öteden geldiğini görmüş olmalısınız. Bunun __file__yerine aklı başında herhangi bir geliştirici gibi referans verin .
Cecil Curry

16

Şunları project/bin/libiçeren bir sarmalayıcı modülü oluşturun :

import sys, os

sys.path.insert(0, os.path.join(
    os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib'))

import mylib

del sys.path[0], sys, os

Ardından, komut dosyalarınızın üstündeki tüm eksiklikleri şu şekilde değiştirebilirsiniz:

#!/usr/bin/python
from lib import mylib

9

Komut dosyası içeriğini herhangi bir şekilde değiştirmek istemiyorsanız, mevcut çalışma dizininin başına .$ PYTHONPATH ekleyin (aşağıdaki örneğe bakın)

PYTHONPATH=.:$PYTHONPATH alembic revision --autogenerate -m "First revision"

Ve buna bir gün diyelim!


docs.python.org/3/tutorial/modules.html#the-module-search-path şunu söylüyor: "sys.path şu konumlardan başlatıldı: -Giriş komut dosyasını içeren dizin". Bunun doğru olmadığını düşünüyorum.

Bunu, özellikle .envrc'de yapma eğilimindeyim, böylece direnv ile bu otomatik ve izole edilmiş.
EdvardM

8

Python 3.4+ kullanma cx_freeze
kullanımını veya IDLE'da kullanmayı engelleme 😃

import sys
from pathlib import Path

sys.path.append(Path(__file__).parent / "lib")

Python2 uyumlu: import pathlib import os sys.path.append (os.path.dirname ( dosya ))
michael

6

Betiği python -milgili kök dizininden çalıştırabilirsiniz . Ve argüman olarak "modül yolunu" iletin.

Misal: $ python -m module.sub_module.main # Notice there is no '.py' at the end.


Başka bir örnek:

$ tree  # Given this file structure
.
├── bar
│   ├── __init__.py
│   └── mod.py
└── foo
    ├── __init__.py
    └── main.py

$ cat foo/main.py
from bar.mod import print1
print1()

$ cat bar/mod.py
def print1():
    print('In bar/mod.py')

$ python foo/main.py  # This gives an error
Traceback (most recent call last):
  File "foo/main.py", line 1, in <module>
    from bar.mod import print1
ImportError: No module named bar.mod

$ python -m foo.main  # But this succeeds
In bar/mod.py

2
Bunu yapmanın önerilen yolu sys yolu kesmek değil m anahtarını kullanmaktır
Mr_and_Mrs_D

4

Verilen her yanıtta, "bu sihirli büyüyü senaryonuzun başına ekleyin. Bir veya iki satır kodla neler yapabileceğinizi görün" şeklinde özetlenebilecek bir sorun var. Mümkün olan her durumda işe yaramayacaklar!

Örneğin, böyle bir büyülü büyü kullanır __file__. Ne yazık ki, betiğinizi cx_Freeze kullanarak paketlerseniz veya IDLE kullanıyorsanız, bu bir istisna ile sonuçlanacaktır.

Bu tür başka bir büyülü büyü os.getcwd () kullanır. Bu, yalnızca betiğinizi komut isteminden çalıştırıyorsanız ve betiğinizi içeren dizin geçerli çalışma diziniyse (yani, komut dosyasını çalıştırmadan önce dizine geçmek için cd komutunu kullandıysanız) çalışır. Eh tanrılar! Umarım Python betiğiniz PATH'de bir yerde ise ve sadece betik dosyanızın adını yazarak çalıştırdıysanız bunun neden işe yaramayacağını açıklamam gerekmiyor.

Neyse ki, test ettiğim tüm durumlarda işe yarayacak büyülü bir büyü var. Ne yazık ki, büyülü büyü, bir veya iki satır koddan daha fazlasıdır.

import inspect
import os
import sys

# Add script directory to sys.path.
# This is complicated due to the fact that __file__ is not always defined.

def GetScriptDirectory():
    if hasattr(GetScriptDirectory, "dir"):
        return GetScriptDirectory.dir
    module_path = ""
    try:
        # The easy way. Just use __file__.
        # Unfortunately, __file__ is not available when cx_Freeze is used or in IDLE.
        module_path = __file__
    except NameError:
        if len(sys.argv) > 0 and len(sys.argv[0]) > 0 and os.path.isabs(sys.argv[0]):
            module_path = sys.argv[0]
        else:
            module_path = os.path.abspath(inspect.getfile(GetScriptDirectory))
            if not os.path.exists(module_path):
                # If cx_Freeze is used the value of the module_path variable at this point is in the following format.
                # {PathToExeFile}\{NameOfPythonSourceFile}. This makes it necessary to strip off the file name to get the correct
                # path.
                module_path = os.path.dirname(module_path)
    GetScriptDirectory.dir = os.path.dirname(module_path)
    return GetScriptDirectory.dir

sys.path.append(os.path.join(GetScriptDirectory(), "lib"))
print(GetScriptDirectory())
print(sys.path)

Gördüğünüz gibi, bu kolay bir iş değil!


1

Bu benim için en iyisi. Kullanım:

os.path.abspath('')

Mac'te aşağıdaki gibi bir şey yazdırmalıdır:

'/Users/<your username>/<path_to_where_you_at>'

Mevcut wd'ye giden abs yolunu elde etmek için bu daha iyidir çünkü şimdi isterseniz yukarı çıkabilirsiniz, örneğin:

os.path.abspath('../')

Ve şimdi:

 '/Users/<your username>/'

Yani utilsburadan içe aktarmak '/Users/<your username>/'
istiyorsanız, yapmanız gereken tek şey:

import sys
sys.path.append(os.path.abspath('../'))

0

Örneğinizde bir mesele görüyorum. Bin komut dosyalarınızı bunun ./bin/foo.pyyerine çalıştırıyorsanız, değişkeni python ./bin/foo.pydeğiştirmek için shebang'ı kullanma seçeneği vardır $PYTHONPATH.

Ortam değişkenlerini doğrudan şekillerde değiştiremezsiniz, bu nedenle küçük bir yardımcı komut dosyasına ihtiyacınız olacaktır. Bu koy python.shsenin içine binklasörde:

#!/usr/bin/env bash
export PYTHONPATH=$PWD/lib
exec "/usr/bin/python" "$@"

Ve sonra, aramalarınızdan shebang değiştirmek ./bin/foo.pyolmak#!bin/python.sh


0

Python dosyasını terminalden yolla çalıştırmaya çalıştığımızda.

import sys
#For file name
file_name=sys.argv[0]
#For first argument
dir= sys.argv[1]
print("File Name: {}, argument dir: {}".format(file_name, dir)

Dosyayı (test.py) kaydedin.

Çalıştırma sistemi.

Terminali açın ve dosyanın kaydedildiği dizine gidin. sonra yaz

python test.py "/home/saiful/Desktop/bird.jpg"

Enter tuşuna basın

Çıktı:

File Name: test, Argument dir: /home/saiful/Desktop/bird.jpg

0

Kullanırım:

from site import addsitedir

Ardından, herhangi bir göreceli dizini kullanabilirsiniz! addsitedir('..\lib') ; iki nokta, bir dizini önce hareket ettirme (yukarı) anlamına gelir.

Unutmayın, her şey mevcut çalışma dizininizin nereden başladığınıza bağlı. Eğer C: \ Joe \ Jen \ Becky ise, C: \ Joe \ Jen \ lib yolunuza addsitedir ('.. \ lib') içe aktarır

C:\
  |__Joe
      |_ Jen
      |     |_ Becky
      |_ lib

Cevabı takdir ediyorum, ancak bu, mevcut çalışan betiğe göre bir yol eklemiyor. Mevcut çalışma dizinine göre bir yol ekler
James Harr
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.