【问题标题】:Reading file using relative path in python project在python项目中使用相对路径读取文件
【发布时间】:2017-03-17 21:32:55
【问题描述】:

假设我有一个结构如下的 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__")?我不想使用绝对路径。有什么方法可以解决这个问题?

【问题讨论】:

  • 作为旁注,引用 PEP8:“非常不鼓励使用相对导入进行包内导入。始终对所有导入使用绝对包路径。” 这里,from package.module import test

标签: python python-3.x io relative-path python-import


【解决方案1】:

相对路径相对于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+,你可以直接使用pathlib.Path:Path(__file__).parent.resolve()
  • 如果你想得到字符串路径,只需str(path)
【解决方案2】:

对于 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)]

【讨论】:

    【解决方案3】:

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

    FileNotFoundError: [Errno 2] No such file or directory
    

    当我从终端运行my_script.py 时。虽然当我通过 PyCharm IDE(PyCharm 2018.3.2(社区版))的运行/调试配置运行它时它运行良好。

    解决方案

    而不是使用:

    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__) 返回一个空字符串“”。这也是为什么my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path 实际上与my_path = some_rel_dir_path 相同的原因。因此在尝试使用open 方法时会给出FileNotFoundError: [Errno 2] No such file or directory,因为没有像“some_rel_dir_path”这样的目录。

    从 PyCharm IDE 运行/调试配置运行脚本有效,因为它运行命令 python3 /full/path/to/my_script.py(其中“/full/path/to”由我们在运行/调试配置的“工作目录”变量中指定),而不仅仅是python3 my_script.py 就像我们从终端运行它一样。

    希望对你有用。

    【讨论】:

    • 这确实是一个警告。显式运行脚本是如此罕见,以至于您似乎是第一个注意到的(通常您会将#!/usr/bin/env python 放在顶部,将其标记为可执行并以./myscript.py 运行它)。 pathlib.Path 版本没有这个问题,但它可能是自 python3.4 以来更好的选择。
    【解决方案4】:

    试试

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

    【讨论】:

      【解决方案5】:

      这对我有用。

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

      【讨论】:

        【解决方案6】:

        当下面的代码运行时,我惊呆了。

        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,它说:

        3.6 版更改:接受类似路径的对象。

        path-like object:

        表示文件系统路径的对象。类似路径的对象是 str 或...

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-30
          • 2019-05-16
          • 1970-01-01
          相关资源
          最近更新 更多