将脚本目录添加到字符串前面

4 投票
3 回答
660 浏览
提问于 2025-04-16 20:46

在写一些临时的小脚本时,通常需要从和脚本在同一个文件夹里的配置文件、图片或者其他东西加载数据。最好是无论脚本从哪个目录执行,这个功能都能正常工作,所以我们可能不想单纯依赖当前的工作目录。

如果在同一个文件里定义一个这样的功能,效果是不错的:

from os.path import abspath, dirname, join

def prepend_script_directory(s):
    here = dirname(abspath(__file__))
    return join(here, s)

不过,把这个功能复制粘贴到每个模块里并不是个好主意,但这里有个问题:如果把它放到一个单独的库里,然后作为一个函数导入,__file__就会指向其他模块,这样结果就不对了。

我们也许可以尝试用这个方法,但看起来sys.argv也不一定可靠。

def prepend_script_directory(s):
    here = dirname(abspath(sys.argv[0]))
    return join(here, s)

那么,如何才能稳妥且正确地写出prepend_script_directory这个功能呢?

3 个回答

-1

你需要用到 pkg_resources 这个工具。

import pkg_resources
foo_fname = pkg_resources.resource_filename(__name__, "foo.txt")
-1

我觉得这里有点不对劲的原因是,$PYTHONPATH(或者说sys.path)是正确的通用方法。

3

我个人的做法是,每次执行脚本时,直接用 os.chdir 切换到脚本所在的目录。这样做很简单:

import os
os.chdir(os.path.split(__file__)[0])

不过,如果你想把这个东西改造成一个库,实际上你就是想要一个能了解调用它的状态的函数。所以你需要让它

prepend_script_directory(__file__, blah)

如果你只是想写

prepend_script_directory(blah)

那么你就得用一些特定于CPython的技巧来处理栈帧:

import inspect

def getCallerModule():
    # gets globals of module called from, and prints out __file__ global
    print(inspect.currentframe().f_back.f_globals['__file__'])

撰写回答