在 python 项目中使用相对路径读取文件

Reading file using relative path in python project

假设我有一个 python 项目,其结构如下:

project
    /data
        test.csv
    /package
        __init__.py
        module.py
    main.py

__init__.py:

from .module import test

module.py:

import csv

with open("..data/test.csv") as f:
    test = [line for line in csv.reader(f)]

main.py:

import package

print(package.test)

当我 运行 main.py 我得到以下错误:

 C:\Users\Patrick\Desktop\project>python main.py
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import package
  File "C:\Users\Patrick\Desktop\project\package\__init__.py", line 1, in <module>
    from .module import test
  File "C:\Users\Patrick\Desktop\project\package\module.py", line 3, in <module>
    with open("../data/test.csv") as f:
FileNotFoundError: [Errno 2] No such file or directory: '../data/test.csv'

但是,如果我从 package 目录中 运行 module.py,我不会收到任何错误。所以似乎 open(...) 中使用的相对路径仅相对于原始文件 运行 来自的位置(即 __name__ == "__main__")?我不想使用绝对路径。有什么方法可以解决这个问题?

相对路径是相对于current working directory。 如果你不希望你的路径是,它必须是绝对的。

但是有一个常用的技巧可以从当前脚本构建绝对路径:使用它的 __file__ 特殊属性:

from pathlib import Path

path = Path(__file__).parent / "../data/test.csv"
with path.open() as f:
    test = list(csv.reader(f))

这需要 python 3.4+(对于 pathlib 模块)。

如果您仍然需要支持旧版本,您可以获得相同的结果:

import csv
import os.path

my_path = os.path.abspath(os.path.dirname(__file__))
path = os.path.join(my_path, "../data/test.csv")
with open(path) as f:
    test = list(csv.reader(f))

[2020编辑: python3.4+现在应该是常态了,所以我搬家了受 jpyams 评论启发的 pathlib 版本]

对于 Python 3.4+:

import csv
from pathlib import Path

base_path = Path(__file__).parent
file_path = (base_path / "../data/test.csv").resolve()

with open(file_path) as f:
    test = [line for line in csv.reader(f)]

我的 Python 版本是 Python 3.5.2 并且接受的答案中提出的解决方案对我不起作用。我仍然收到错误消息

FileNotFoundError: [Errno 2] No such file or directory

当我从终端 运行ning my_script.py 时。尽管当我通过 PyCharm IDE(PyCharm 2018.3.2(社区版))的 Run/Debug 配置时 运行 它工作正常。

解决方案:

而不是使用:

my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path 

按照接受的答案中的建议,我使用了:

my_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) + some_rel_dir_path

说明: 将 os.path.dirname(__file__) 更改为 os.path.dirname(os.path.abspath(__file__)) 解决了以下问题:

当我们 运行 我们的脚本是这样的:python3 my_script.py __file__ 变量只有一个 "my_script.py" 的字符串值,没有指向该特定脚本的路径。这就是为什么方法 dirname(__file__) returns 一个空字符串“”。这也是 my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path 实际上与 my_path = some_rel_dir_path 相同的原因。因此 FileNotFoundError: [Errno 2] No such file or directory 在尝试使用 open 方法时给出,因为没有像 "some_rel_dir_path".

这样的目录

运行 来自 PyCharm IDE Running/Debug 的脚本配置有效,因为它 运行 是一个命令 python3 /full/path/to/my_script.py(其中“/full/path/to" 是由我们在 Run/Debug 配置中的 "Working directory" 变量中指定的),而不是像我们从终端 运行 它时所做的那样只是 python3 my_script.py

希望有用。

尝试

with open(f"{os.path.dirname(sys.argv[0])}/data/test.csv", newline='') as f:

这对我有用。

with open('data/test.csv') as f:

 

当下面的代码起作用时,我惊呆了。

import os

for file in os.listdir("../FutureBookList"):
    if file.endswith(".adoc"):
        filename, file_extension = os.path.splitext(file)
        print(filename)
        print(file_extension)
        continue
    else:
        continue

所以,我检查了 documentation,它说:

Changed in version 3.6: Accepts a path-like object.

path-like object:

An object representing a file system path. A path-like object is either a str or...

我做了一个 little more digging 并且以下也有效:

with open("../FutureBookList/file.txt") as file:
   data = file.read()