Python 从自定义路径打开文件名

Python open filename from custom PATH

与系统路径类似,我想在我的代码中提供一些便利,允许用户指定可以位于少数几个路径之一的文件名。

假设我有两个或更多配置路径

['~/.foo-config/', '/usr/local/myapp/foo-config/']

我的用户想要打开 bar,(又名 bar.baz

  1. 是否有方便的构建方式让 open('bar')open('bar.baz') 自动按照 LTR 优先顺序在这些路径中搜索该文件?例如,将我的 sys.path 临时调整为仅这些目录会为我执行此操作吗?

  2. 否则,您建议如何实现类似 PATH 的搜索打开包装程序?

环境变量

假设您的应用名为 foo ... 在自述文件中告诉用户使用 FOO_PATH 环境变量来指定额外路径

然后在您的应用中执行类似

的操作
 for path in os.environ.get("FOO_PATH",".").split(";"):
     lookfor(os.path.join(path,"somefile.txt"))

你可以把它包装成一个通用函数

def open_foo(fname):
   for path in os.environ.get("FOO_PATH",".").split(";"):
       path_to_test = os.path.join(path,"somefile.txt")
       if os.path.exists(path_to_test):
              return open(path_to_test)
   raise Exception("No File Found On FOOPATH")

然后就可以像正常打开一样使用了

with open_foo("my_config.txt") as f:
     print f.read()

open 不会进入那种逻辑。如果需要,可以编写一个包装函数,使用 os.path.joinsys.path 的每个成员连接到参数文件名,并尝试按顺序打开它们,处理在找不到此类文件时发生的错误。

我要补充一点,正如另一位用户所说,这是对 sys.path 的一种误用,但此功能适用于任何路径列表。事实上,也许最好的选择是使用另一个用户建议的环境变量来指定一个以冒号分隔的配置目录列表,然后您可以在搜索功能中解析和使用它。

正如其他人已经提到的:sys.path 影响模块搜索路径,即它与导入 Python 模块相关,但根本不影响open().

我建议将搜索路径的逻辑按优先顺序和打开文件分开,因为这样更容易 testread.

我会这样做:

import os

PATHS = ['~/.foo-config/', '/usr/local/myapp/foo-config/']


def find_first(filename, paths):
    for directory in paths:
        full_path = os.path.join(directory, filename)
        if os.path.isfile(full_path):
            return full_path


def main():
    filename = 'file.txt'
    path = find_first(filename, PATHS)
    if path:
        with open(path) as f:
            print f
    else:
        print "File {} not found in any of the directories".format(filename)


if __name__ == '__main__':
    main()

摘自 Python open built-in function 的标准库文档:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

...file 是字符串或字节对象,给出要打开的文件的路径名(绝对或相对于当前工作目录) ...

明确地说,open 不会带来任何自动查找文件的功能:如果路径不是绝对路径,则只会在当前目录中搜索。

因此您必须为此使用自定义函数或自定义 class。例如:

class path_opener(object):
    def __init__(self, path = [.]):
        self.path = path
    def set(self, path):
        self.path = path
    def append(self, path):
        self.path.append(path)
    def extent(self, path):
        self.path.extend(path)
    def find(self, file):
        for folder in self.path:
            path = os.path.join(folder, file)
            if os.path.isfile(path):
                return path
        raise FileNotFoundError()
    def open(self, file, *args, **kwargs):
        return open(self.find(file), *args, **kwargs)

这意味着文件打开器将保留其自己的 路径,默认情况下将使用当前路径进行初始化,将具有设置、追加或扩展其路径的方法,并且如果在其路径中列出的任何目录中都找不到文件,通常会引发 FileNotFoundError。

用法:

o = path_opener(['~/.foo-config/', '/usr/local/myapp/foo-config/'])
with o.open('foo') as fd:
    ...