Python:現在実行中のスクリプトに関連してsys.pathに追加する最良の方法


96

スクリプトでいっぱいのディレクトリがあります(たとえば、としましょうproject/bin)。また、ライブラリがありproject/lib、スクリプトが自動的にそれをロードするようにしたいと思っています。これは、私が各スクリプトの上部で通常使用するものです。

#!/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

これはちょっと面倒で見苦しく、すべてのファイルの最初に貼り付ける必要があります。これを行うより良い方法はありますか?

本当に私が望んでいるのは、このようにスムーズなものです:

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

import mylib

または、さらに良いことに、私の編集者(またはコミットアクセス権を持つ他の誰か)が、クリーンアッププロセスの一環としてインポートの順序を変更することを決定しても壊れないもの:

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

それは非POSIXプラットフォームに直接移植しないでしょう、しかしそれは物事をきれいに保ちます。


回答:


25

各ファイルを編集したくない場合

  • 通常のpython librayのようにライブラリをインストールする
    か、
  • 設定するPYTHONPATHには、あなたのlib

または、各ファイルに1行を追加する場合は、先頭にインポートステートメントを追加します。

import import_my_lib

import_my_lib.pyビンに保管しimport_my_lib、Pythonパスを必要なものに正しく設定できlibます


118

これは私が使用するものです:

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

2
他のパスによって上書きされないように、sys.path.insert(0、..)を実行します。
ジョンジャン

これを自動的に実行する方法は本当にありませんか?
Denis de Bernardy

1
これは少し危険です。場合は__file__、現在の作業ディレクトリ(たとえば、に対する相対ファイル名ですsetup.py)、その後os.path.dirname(__file__)になります空の文字列。John Jiangによって提起されたこのような同様の懸念については、ekhumoroより汎用的なソリューションが強く推奨されます。
セシルカレー

27

私が使用しています:

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

4
私はよくやるだけですsys.path.append('.')
kimbo

1
スクリプトが別のディレクトリから実行されている場合はどうなりますか?たとえば、完全なシステムパスを指定してルートディレクトリから?その後、os.getcwd()は「/」を返します
obayhan

2
絶対にしないでください。現在の作業ディレクトリ(CWD)が、あなたが思っているとおりであるとは限りません。特に、予想外のエッジケースの場合、1マイル離れた場所で表示されるはずでした。__file__代わりに、他の準正気な開発者と同じように参照してください。
セシルカレー

14

project/bin/libこれを含むラッパーモジュールを作成します。

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

次に、スクリプトの上部にあるすべての残骸を次のものに置き換えます。

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

8

スクリプトの内容をなんらかの方法で変更したくない場合は、現在の作業ディレクトリ.を$ PYTHONPATHに付加します(以下の例を参照)。

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

そして、それを1日と呼びます!


docs.python.org/3/tutorial/modules.html#the-module-search-pathのコメント:「sys.pathは次の場所から初期化されます:-入力スクリプトを含むディレクトリ」。これは本当ではないと思います。

私は特に.envrcでこれを行う傾向があるため、direnvを使用しても自動で分離されます。
EdvardM

8

Python 3.4以降の使用 cx_freeze
の使用またはIDLEでの使用を禁止します。😃

import sys
from pathlib import Path

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

Python2互換性:インポートpathlibインポートOSのsys.path.append(os.path.dirname(ファイル))
マイケル・

5

python -m関連するルートディレクトリからスクリプトを実行できます。そして、「モジュールパス」を引数として渡します。

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


もう一つの例:

$ 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

1
m個のスイッチを使用すると、SYSパスハック推奨これを行う方法とではありません
Mr_and_Mrs_D

4

「この魔法の呪文をスクリプトの先頭に追加するだけです。1行か2行のコードで何ができるかを見てください」と要約できるすべての回答に問題があります。彼らはすべての可能な状況で動作するとは限りません!

たとえば、そのような魔法の呪文はfileを使用します。残念ながら、cx_Freezeを使用してスクリプトをパッケージ化したり、IDLEを使用したりすると、例外が発生します。

別のそのような魔法の呪文はos.getcwd()を使用します。これは、コマンドプロンプトからスクリプトを実行していて、スクリプトを含むディレクトリが現在の作業ディレクトリである場合にのみ機能します(つまり、スクリプトを実行する前に、cdコマンドを使用してディレクトリに移動します)。神様!PythonスクリプトがPATHのどこかにあり、スクリプトファイルの名前を入力するだけで実行された場合、これが機能しない理由を説明する必要がないことを願っています。

幸い、私がテストしたすべてのケースで機能する魔法の呪文があります。残念ながら、魔法の呪文は、1行または2行のコード以上のものです。

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)

ご覧のとおり、これは簡単な作業ではありません。


0

これは私に最適です。使用する:

os.path.abspath('')

Macでは次のように表示されます。

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

現在のwdへのabsパスを取得するには、次のように、必要に応じて上に移動できるため、これがより適切です。

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

そして今:

 '/Users/<your username>/'

したがってutils、ここからインポートする'/Users/<your username>/'
場合は、あとは次のことだけです。

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

0

あなたの例ではシバンが見えます。binスクリプトを./bin/foo.pyではなくとして実行してpython ./bin/foo.pyいる場合、$PYTHONPATH変数を変更するためにシバンを使用するオプションがあります。

ただし、シバンで直接環境変数を変更することはできないため、小さなヘルパースクリプトが必要になります。これpython.shをあなたのbinフォルダに入れてください:

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

そして、あなたのシェバングを変更./bin/foo.pyします#!bin/python.sh


0

端末からのパスを使用してpythonファイルを実行しようとすると、

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)

ファイル(test.py)を保存します。

ランニングシステム。

ターミナルを開いて、ファイルが保存されているディレクトリに移動します。次に書く

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

Enterキーを押す

出力:

File Name: test, Argument dir: /home/saiful/Desktop/bird.jpg
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.