204

我们正在使用部署到 Windows 和 Linux 的代码存储库 - 有时位于不同的目录中。项目内部的模块之一应该如何引用项目中的非 Python 资源之一(CSV 文件等)?

如果我们这样做:

thefile = open('test.csv')

或者:

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

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

我想做的是:

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

是否可以?

4

9 回答 9

280

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

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

在 Python 3.4+ 中,您还可以使用pathlib

fn = pathlib.Path(__file__).parent / 'my_file'
于 2009-08-13T09:27:28.263 回答
48

如果您使用安装工具或分发(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

于 2012-02-07T14:24:07.670 回答
21

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

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

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')
于 2017-03-25T03:04:35.800 回答
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 不同。

于 2009-08-13T12:11:19.423 回答
6
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

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

于 2009-08-13T09:40:27.410 回答
2

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

于 2009-08-13T09:28:40.977 回答
1

我在这里有点难过。想把一些资源文件打包成一个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

清单文件

recursive-include cnn_client/resources *

使用标准 setup.py 创建了一个 weel。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()

它有效。

于 2019-05-13T09:24:13.177 回答
0

既然你说你有一些代码要部署到各个地方,那么你应该使用python生态系统来分发资源,这不仅限于文件。它还支持访问 zip 档案中的文件,这很好,因此您不必为此烦恼。

以前,这是用pkg_resourcesfrom处理的setuptools,但随着越来越多的工具出现,生态系统已经发生了变化。从 python 3.7 开始,您应该使用importlib.resources

import importlib.resources
with importlib.resources.open_text('mypackage.somedirectory','text.csv') as f:
    print(f.read()) # or whatever

但是您还必须指示安装程序包括包资源。否则,apip install mypackage不会捆绑数据文件。

有很多方法可以做到这一点,但一种方法是添加

[options.package_data]
mypackage = 
    "somedirectory/*.csv"

进入你的setup.cfg. setup.py使用or时有等效的方法pyproject.tomlsetuptools 主页上提供了更完整的帐户

于 2021-10-20T13:41:37.700 回答
-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 的目录中查看它非常快速和肮脏,但它就像一个魅力:)

于 2011-02-02T12:43:48.627 回答