在Python中使用代码存储库时如何引用资源的相对路径

How to refer to relative paths of resources when working with a code repository in Python

我们正在使用一个同时部署到Windows和Linux的代码存储库——有时在不同的目录上。项目中的一个模块应该如何引用项目中的一个非python资源(csv文件等)?

如果我们做类似的事情:

1
thefile=open('test.csv')

或:

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

只有当脚本从一个特定目录或目录的一个子集运行时,它才会工作。

我想做的是:

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

这条路对吗?有可能吗?


尝试使用相对于当前文件路径的文件名。'/my_file'示例:

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

在python 3.4+中,还可以使用pathlib:

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


如果您使用安装工具或分发(setup.py安装),那么访问这些打包资源的"正确"方法似乎是使用包资源。

在你的例子中,例子是

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

哪个读取资源和读取的二进制数据将是我的数据的值?

如果您只需要文件名,也可以使用

1
resource_filename(package_or_requirement, resource_name)

例子:

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

其优势在于,即使是像鸡蛋一样的档案分发,它也能保证工作正常。

请参阅http://packages.python.org/distribute/pkg_resources.html resourcemanager api


我经常用类似的东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
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))
    # ...

变量

1
__file__

保留编写该代码的脚本的文件名,以便可以相对于脚本创建路径,但仍使用绝对路径编写。它工作得很好,原因有几个:

  • 路径是绝对的,但仍然是相对的
  • 项目仍然可以部署在相对容器中

但您需要注意平台兼容性-Windows的os.pathsep与Unix不同。


在python中,路径是相对于当前工作目录的,在大多数情况下,这是运行程序的目录。当前工作目录很可能与模块文件的目录不同,因此使用相对于当前模块文件的路径总是一个错误的选择。

使用绝对路径应该是最佳解决方案:

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

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

您还尝试使用os.path.abspath(os.getcwd())规范化您的cwd。更多信息在这里。


您可以使用内置的__file__变量。它包含当前文件的路径。我将在您的项目根目录中的一个模块中实现getbaseofproject。在那里,我会得到EDOCX1的路径部分(0),然后返回。然后这个方法可以在项目的任何地方使用。


我在这里受了点挫折。想要将一些资源文件打包成一个轮子文件并访问它们。使用清单文件进行打包,但PIP安装没有安装它,除非它是子目录。希望这些权杖能有帮助

1
2
3
4
5
6
7
8
├── 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

1
recursive-include cnn_client/resources *

使用standard setup.py创建了一个WEEL。PIP安装了车轮文件。安装后检查是否安装了资源。他们是

1
2
3
4
5
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中访问这些文件。从

1
2
3
4
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()

它起作用了。


我花了很长时间想清楚这个问题的答案,但最终我得到了它(实际上很简单):

1
2
3
4
5
6
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查找的目录中。它很快又脏,但它的作用就像一个魅力:)