我过去常常打开与当前运行的Python脚本在同一目录下的文件,只需使用如下命令:

open("Some file.txt", "r")

然而,我发现当在Windows中双击该脚本时,它会试图从错误的目录打开文件。

从那以后,我一直使用表单的命令

open(os.path.join(sys.path[0], "Some file.txt"), "r")

每当我想打开一个文件。这适用于我的特定用法,但我不确定sys。路径[0]可能在其他用例中失败。

所以我的问题是:打开与当前运行的Python脚本位于同一目录下的文件的最佳和最可靠的方法是什么?

以下是我目前所了解到的情况:

os.getcwd() and os.path.abspath('') return the "current working directory", not the script directory. os.path.dirname(sys.argv[0]) and os.path.dirname(__file__) return the path used to call the script, which may be relative or even blank (if the script is in the cwd). Also, __file__ does not exist when the script is run in IDLE or PythonWin. sys.path[0] and os.path.abspath(os.path.dirname(sys.argv[0])) seem to return the script directory. I'm not sure if there's any difference between these two.

编辑:

我刚刚意识到,我想做的事情应该更好地描述为“在包含模块的同一目录中打开一个文件”。换句话说,如果我导入了一个我在另一个目录下编写的模块,而该模块打开了一个文件,我希望它在模块的目录下查找该文件。我不认为我发现的任何东西都能做到这一点……


当前回答

引用Python文档:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

如果从终端运行脚本,则sys. exe。路径[0]就是你要找的。

然而,如果你有:

barpath/bar.py
    import foopath.foo

foopath/foo.py
    print sys.path[0]  # you get barpath

所以要小心!

其他回答

我通常使用以下方法。它适用于测试,也可能适用于其他用例。

使用open(os.path.join(os.path.dirname(__file__), 'some_file.txt'), 'r')作为f:

建议登录https://stackoverflow.com/questions/10174211/how-to-make-an-always-relative-to-current-module-file-path


在Python 3.4中,添加了pathlib模块,下面的代码将可靠地打开与当前脚本相同目录下的文件:

from pathlib import Path

p = Path(__file__).with_name('file.txt')
with p.open('r') as f:
    print(f.read())

如果你需要文件路径作为一个字符串来使用一些类似开放的API,你可以使用absolute():

p = Path(__file__).with_name('file.txt')
filename = p.absolute()

注意:Python reps,如运行Python命令而不带目标或ipython,不会公开__file__。

因为我在尝试使用__file__或sys。我是这样做的:

from inspect import getfile
from pathlib import Path


script_path = getfile(lambda: None)
print(script_path)
parent_path = Path(script_path).parent
print(parent_path)

with open(parent_path/'Some file.txt', 'r') as obFile:
    print(obFile.read())

引用Python文档:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

如果从终端运行脚本,则sys. exe。路径[0]就是你要找的。

然而,如果你有:

barpath/bar.py
    import foopath.foo

foopath/foo.py
    print sys.path[0]  # you get barpath

所以要小心!

我是这么做的

sys。Argv始终是你输入到终端或使用python.exe或pythonw.exe执行时使用的文件路径

例如,你可以用几种方式运行文件text.py,它们都会给你不同的答案它们总会给你python输入的路径。

    C:\Documents and Settings\Admin>python test.py
    sys.argv[0]: test.py
    C:\Documents and Settings\Admin>python "C:\Documents and Settings\Admin\test.py"
    sys.argv[0]: C:\Documents and Settings\Admin\test.py

你可以知道文件名,这很重要,现在要知道应用目录你可以使用os。路径,特别是abspath和dirname

    import sys, os
    print os.path.dirname(os.path.abspath(sys.argv[0]))

这将输出:

   C:\Documents and Settings\Admin\

不管你输入的是python test.py还是python "C:\Documents and Settings\Admin\test.py"

使用__file__的问题 考虑以下两个文件 test.py

import sys
import os

def paths():
        print "__file__: %s" % __file__
        print "sys.argv: %s" % sys.argv[0]

        a_f = os.path.abspath(__file__)
        a_s = os.path.abspath(sys.argv[0])

        print "abs __file__: %s" % a_f
        print "abs sys.argv: %s" % a_s

if __name__ == "__main__":
    paths()

import_test.py

import test
import sys

test.paths()

print "--------"
print __file__
print sys.argv[0]

"python test.py"输出

C:\Documents and Settings\Admin>python test.py
__file__: test.py
sys.argv: test.py
abs __file__: C:\Documents and Settings\Admin\test.py
abs sys.argv: C:\Documents and Settings\Admin\test.py

python test_import.py的输出

C:\Documents and Settings\Admin>python test_import.py
__file__: C:\Documents and Settings\Admin\test.pyc
sys.argv: test_import.py
abs __file__: C:\Documents and Settings\Admin\test.pyc
abs sys.argv: C:\Documents and Settings\Admin\test_import.py
--------
test_import.py
test_import.py

如你所见,file总是给你运行它的python文件,而sys。Argv[0]给出了你总是从解释器运行的文件。根据你的需要,你需要选择一个最适合你的需求。