コードリポジトリを操作するときにリソースの相対パスを参照する方法


187

WindowsとLinuxの両方にデプロイされているコードリポジトリを使用しています。プロジェクト内のモジュールの1つがプロジェクト内の非Pythonリソース(CSVファイルなど)の1つをどのように参照する必要がありますか?

次のようなことをした場合:

thefile=open('test.csv')

または:

thefile=open('../somedirectory/test.csv')

スクリプトが特定の1つのディレクトリまたはディレクトリのサブセットから実行された場合にのみ機能します。

私がしたいのは次のようなものです:

path=getBasePathOfProject()+'/somedirectory/test.csv'
thefile=open(path)

出来ますか?

回答:


255

現在のファイルパスに関連するファイル名を使用してみてください。'./my_file'の例:

fn = os.path.join(os.path.dirname(__file__), 'my_file')

Pythonでは3.4+使うこともできpathlibを

fn = pathlib.Path(__file__).parent / 'my_file'

3
この解決策は、リソースがpythonファイルの同じディレクトリ、またはそのサブディレクトリにある場合にのみ機能すると思います。次のツリー構造がある場合、どのように解決しますか:/ Project_Root_dir / python_files_dir / Some more subdirs here py_file.py / resources / some subdirs here resource_file.csv
olamundo

1
最後のメッセージでファイルツリーが文字化けしました... 2回目:/Project_Root_dir/python_files_dir/some_subdirs/py_file.pyにファイルがあり、/ Project_Root_dir / resources / some_subdirs
オラムンド

28
join(foo、 '..')を使用して親ディレクトリにアクセスできるはずです。そのため、/ root / python_files / module / myfileから、os.path.join(os.path.dirname(__file__)、 '..'、 '..'、 'resources')を使用します
c089

7
os.pardir'..'2つはPOSIXとWindowsの両方で同等ですが、は少し優れています。
davidchambers 2013年

4
@cedbeu:私が遭遇したすべてのシステムで同等であり、今日すべてのシステムpythonが実行されていると思います(ここで間違っている場合は修正してください)。ただし、将来的に別のパス区切り文字を使用するシステムにpythonを移植する予定で、コードを準備できるようにしたい場合は、os.pardirの方が移植性が高くなります。私はすべてのプログラマー、どんなpythonも読んだことがない人でも ".."の意味を知っていると思いますが、 "os.pardir"は間接的にドキュメントを調べなければならないレベルです。 d「..」に固執する。
c089 2013年

40

セットアップツールを使用している場合、または配布(setup.pyインストール)している場合、これらのパッケージ化されたリソースにアクセスする「正しい」方法は、package_resourcesを使用しているようです。

あなたの場合、例は

import pkg_resources
my_data = pkg_resources.resource_string(__name__, "foo.dat")

もちろん、どちらがリソースを読み取り、読み取ったバイナリデータがmy_dataの値になります。

ファイル名が必要なだけなら、あなたも使うことができます

resource_filename(package_or_requirement, resource_name)

例:

resource_filename("MyPackage","foo.dat")

利点は、それが卵のようなアーカイブ配布であっても動作することが保証されていることです。

http://packages.python.org/distribute/pkg_resources.html#resourcemanager-apiを参照してください


3
私はこれが古い答えであることを知っています、pkg_resourcesを使用するのが私の方法です(/ was多分?)__file__
Pykler、2014

1
これはしっかりしたアプローチです。egg規約が廃止された場合でも、setuptoolsは廃止されず、実行時に卵がビルドされるgit reposに対してdepsをインストールしている人がいます
deepelement

18

Pythonでは、パスは現在の作業ディレクトリからの相対パスです。これは、ほとんどの場合、プログラムを実行するディレクトリです。現在の作業ディレクトリは、現在のモジュールファイルへの相対パスを使用すると、常に悪い選択であるので、非常に可能性があなたのモジュールファイルのディレクトリと同じではありません。

絶対パスを使用するのが最善の解決策です。

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')

15

私はよくこれに似たものを使います:

import os
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir'))

# if you have more paths to set, you might want to shorten this as
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x))
DATA_DIR = here('datadir') 

pathjoin = os.path.join
# ...
# later in script
for fn in os.listdir(DATA_DIR):
    f = open(pathjoin(DATA_DIR, fn))
    # ...

変数

__file__

そのコードを記述したスクリプトのファイル名を保持するため、スクリプトからの相対パスを作成できますが、絶対パスを使用して記述できます。それはいくつかの理由でかなりうまくいきます:

  • パスは絶対ですが、それでも相対パスです
  • プロジェクトはまだ相対コンテナにデプロイできます

ただし、プラットフォームの互換性に注意する必要があります。Windowsのos.pathsepはUNIXとは異なります。


4
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

また、cwdを使用して正規化しようとしますos.path.abspath(os.getcwd())。詳細はこちら


3
ただし、the cwdがモジュールのパスであるユースケースはほとんどありません
cedbeu

スクリプトによって設定された同じディレクトリ(または作業ディレクトリ)からのみ、パッケージ内では機能しません。
アレクサンドラ

ユーザーが別のディレクトリからの絶対パスを使用してプログラムを実行する場合、これは機能しません。例:python3 /usr/someone/test.py
sgrpwr

2

ビルドイン__file__変数を使用できます。現在のファイルのパスが含まれています。プロジェクトのルートのモジュールにgetBaseOfProjectを実装します。そこでパスの部分を取得し、__file__それを返します。この方法は、プロジェクトのどこでも使用できます。


0

ここで少し困惑した。一部のリソースファイルをWheelファイルにパッケージ化してアクセスしたかった。マニフェストファイルを使用してパッケージを作成しましたが、サブディレクトリでない限り、pip installはそれをインストールしませんでした。これらの鋭いショットが役立つことを願って

├── cnn_client
   ├── image_preprocessor.py
   ├── __init__.py
   ├── resources
      ├── mscoco_complete_label_map.pbtxt
      ├── retinanet_complete_label_map.pbtxt
      └── retinanet_label_map.py
   ├── tf_client.py

MANIFEST.in

recursive-include cnn_client/resources *

標準のsetup.pyを使用してウィールを作成しました。pipはwheelファイルをインストールしました。インストール後に、リソースがインストールされているかどうかを確認しました。彼らです

ls /usr/local/lib/python2.7/dist-packages/cnn_client/resources

mscoco_complete_label_map.pbtxt
retinanet_complete_label_map.pbtxt 
 retinanet_label_map.py  

これらのファイルにアクセスするtfclient.py内。から

templates_dir = os.path.join(os.path.dirname(__file__), 'resources')
 file_path = os.path.join(templates_dir, \
            'mscoco_complete_label_map.pbtxt')
        s = open(file_path, 'r').read()

そしてそれは機能します。


-5

私はこれに対する答えを理解するのに長い時間を費やしましたが、ついにそれを手に入れました(そしてそれは実際には本当に簡単です):

import sys
import os
sys.path.append(os.getcwd() + '/your/subfolder/of/choice')

# now import whatever other modules you want, both the standard ones,
# as the ones supplied in your subfolders

これにより、Pythonが検索するディレクトリにサブフォルダーの相対パスが追加されます。これはかなり速くて汚いですが、魅力のように機能します:)


6
これは、問題の.pyファイルと同じディレクトリからPythonプログラムを実行している場合にのみ機能します。その場合は、open('your/subfolder/of/choice')とにかく行うことができます。
ポールフィッシャー

4
OPは、コードはWindowsとLinuxの両方で機能する必要があると述べました。これはしません。
user183037 2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.