Python:从其他文件的工作目录执行execfile?

7 投票
1 回答
8655 浏览
提问于 2025-04-15 16:28

我有一段代码,它会加载一个默认的配置文件,然后允许用户提供自己的Python文件,作为额外的配置或者覆盖默认设置:

# foo.py

def load(cfg_path=None):
    # load default configuration
    exec(default_config)

    # load user-specific configuration
    if cfg_path:
        execfile(cfg_path)

不过,这里有个问题:execfile()会在foo.py的工作目录下执行cfg_path指定的文件里的指令,而不是在它自己的工作目录下。因此,如果cfg_path文件里有类似from m import x的导入指令,而m是和cfg_path在同一个目录下的模块,那么这个导入可能会失败。

我该如何在execfile()中使用它参数的工作目录,或者以其他方式达到相同的效果?另外,我听说在Python 3中execfile已经不推荐使用了,应该用exec,所以如果有更好的方法,我非常乐意听取。

注意:我认为仅仅改变工作目录的解决方案是不正确的。因为这样做不会把那些模块放到解释器的模块查找路径中,至少从我看来是这样的。

1 个回答

7

os.chdir 这个功能可以让你随意更改当前的工作目录(你可以用 os.path.dirname 来提取 cfg_path 的工作目录);如果你想在执行完 cfg_path 后恢复到之前的目录,记得先用 os.getcwd 获取当前目录。

Python 3 确实去掉了 execfile 这个功能(改为先读取文件,再 compile 内容,最后 exec 执行),但如果你现在用的是 Python 2.6,就不用担心这个问题,因为 2to3 工具可以很顺利地处理这些转换。

补充说明:提问者在评论中说 execfile 会启动一个单独的进程,并且不管当前的工作目录。这是错误的,下面有个例子可以证明这一点:

import os

def makeascript(where):
  f = open(where, 'w')
  f.write('import os\nprint "Dir in file:", os.getcwd()\n')
  f.close()

def main():
  where = '/tmp/bah.py'
  makeascript(where)
  execfile(where)
  os.chdir('/tmp')
  execfile(where)

if __name__ == '__main__':
  main()

在我的机器上运行这个会产生如下输出:

Dir in file: /Users/aleax/stko
Dir in file: /private/tmp

这清楚地表明 execfile 确实会使用在执行 execfile 时设置的工作目录。(如果被执行的文件更改了工作目录,这个变化会在 execfile 返回后体现出来——因为所有操作都是在同一个进程中进行的!)

所以,提问者所遇到的任何问题都与当前的工作目录无关(要诊断他们实际遇到的问题是很困难的,因为没有看到代码和具体的错误细节;-)。

撰写回答