Similar to the system path, I want to offer some convenience in my code allowing a user to specify a file name that could be in one of a handful of paths.
与系统路径类似,我希望在代码中提供一些便利,允许用户指定可以在少数路径之一中的文件名。
Say I had two or more config paths
假设我有两个或更多配置路径
['~/.foo-config/', '/usr/local/myapp/foo-config/']
And my user wants to open bar
, (AKA bar.baz
)
我的用户想打开吧,(AKA bar.baz)
-
Is there a convenient build in way to letopen('bar')
oropen('bar.baz')
automatically search these paths for that file in LTR order of precedence? Eg, will temporary adjusting mysys.path
to only be these directories do this for me?是否有方便的构建让open('bar')或open('bar.baz')以LTR优先顺序自动搜索这些文件的路径?例如,将临时调整我的sys.path只是这些目录为我做这个吗?
-
Else, how would you suggest implementing a PATH-like searching open-wrapper?
否则,您如何建议实现类似PATH的搜索开放包装器?
4 个解决方案
#1
open
doesn't get into that kind of logic. If you want, write a wrapper function that uses os.path.join
to join each member of sys.path
to the parameter filename, and tries to open them in order, handling the error that occurs when no such file is found.
open并没有进入那种逻辑。如果需要,编写一个包装函数,使用os.path.join将sys.path的每个成员连接到参数文件名,并尝试按顺序打开它们,处理没有找到此类文件时发生的错误。
I'll add that, as another user stated, this is kind of a misuse of sys.path
, but this function would work for any list of paths. Indeed, maybe the nicest option is to use the environment variables suggested by another user to specify a colon-delimited list of config directories, which you then parse and use within your search function.
我将补充一点,正如另一位用户所说,这是对sys.path的误用,但是这个函数适用于任何路径列表。实际上,最好的选择可能是使用另一个用户建议的环境变量来指定以冒号分隔的配置目录列表,然后在搜索功能中对其进行解析和使用。
#2
As other people already mentioned: sys.path
only affects the module search path, i.e. it's relevant for importing Python modules, but not at all for open()
.
正如其他人已经提到的:sys.path只影响模块搜索路径,即它与导入Python模块相关,但对open()完全没有影响。
I would suggest separating the logic for searching the paths in order of precedence and opening the file, because that way it's easier to test and read.
我建议按优先顺序分开搜索路径的逻辑并打开文件,因为这样更容易测试和读取。
I would do something like this:
我会做这样的事情:
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()
#3
environmental variables
say your app is named foo ... in the readme tell the user to use the FOO_PATH environmental variable to specify the extra paths
假设您的应用程序名为foo ...在自述文件中告诉用户使用FOO_PATH环境变量来指定额外路径
then inside your app do something like
然后在你的应用程序内做类似的事情
for path in os.environ.get("FOO_PATH",".").split(";"):
lookfor(os.path.join(path,"somefile.txt"))
you could wrap it into a generic function
你可以将它包装成一个通用函数
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")
then you could use it just like normal open
然后你可以像普通开放一样使用它
with open_foo("my_config.txt") as f:
print f.read()
#4
Extract from Python Standard Library documentation for open built-in function:
从Python标准库文档中提取开放内置函数:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
open(file,mode ='r',buffering = -1,encoding = None,errors = None,newline = None,closefd = True,opener = None)
...file is either a string or bytes object giving the pathname (absolute or relative to the current working directory) of the file to be opened ...
... file是字符串或字节对象,给出要打开的文件的路径名(绝对或相对于当前工作目录)...
Explicitely, open does not bring anything to automagically find a file : if path is not absolute, it is only searched in current directory.
显而易见,open不会带来任何自动查找文件的内容:如果path不是绝对的,则只在当前目录中搜索。
So you will have to use a custom function or a custom class for that. For example:
因此,您必须使用自定义函数或自定义类。例如:
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)
That means that a file opener will keep its own path, will be initialized by default with current path, will have methods to set, append to or extend its path, and will normaly raise a FileNotFoundError is a file is not found in any of the directories listed in its path.
这意味着文件开启器将保留自己的路径,默认情况下将使用当前路径进行初始化,将具有设置,追加或扩展其路径的方法,并且将正常引发FileNotFoundError是在任何文件中找不到的其路径中列出的目录。
Usage :
o = path_opener(['~/.foo-config/', '/usr/local/myapp/foo-config/'])
with o.open('foo') as fd:
...
#1
open
doesn't get into that kind of logic. If you want, write a wrapper function that uses os.path.join
to join each member of sys.path
to the parameter filename, and tries to open them in order, handling the error that occurs when no such file is found.
open并没有进入那种逻辑。如果需要,编写一个包装函数,使用os.path.join将sys.path的每个成员连接到参数文件名,并尝试按顺序打开它们,处理没有找到此类文件时发生的错误。
I'll add that, as another user stated, this is kind of a misuse of sys.path
, but this function would work for any list of paths. Indeed, maybe the nicest option is to use the environment variables suggested by another user to specify a colon-delimited list of config directories, which you then parse and use within your search function.
我将补充一点,正如另一位用户所说,这是对sys.path的误用,但是这个函数适用于任何路径列表。实际上,最好的选择可能是使用另一个用户建议的环境变量来指定以冒号分隔的配置目录列表,然后在搜索功能中对其进行解析和使用。
#2
As other people already mentioned: sys.path
only affects the module search path, i.e. it's relevant for importing Python modules, but not at all for open()
.
正如其他人已经提到的:sys.path只影响模块搜索路径,即它与导入Python模块相关,但对open()完全没有影响。
I would suggest separating the logic for searching the paths in order of precedence and opening the file, because that way it's easier to test and read.
我建议按优先顺序分开搜索路径的逻辑并打开文件,因为这样更容易测试和读取。
I would do something like this:
我会做这样的事情:
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()
#3
environmental variables
say your app is named foo ... in the readme tell the user to use the FOO_PATH environmental variable to specify the extra paths
假设您的应用程序名为foo ...在自述文件中告诉用户使用FOO_PATH环境变量来指定额外路径
then inside your app do something like
然后在你的应用程序内做类似的事情
for path in os.environ.get("FOO_PATH",".").split(";"):
lookfor(os.path.join(path,"somefile.txt"))
you could wrap it into a generic function
你可以将它包装成一个通用函数
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")
then you could use it just like normal open
然后你可以像普通开放一样使用它
with open_foo("my_config.txt") as f:
print f.read()
#4
Extract from Python Standard Library documentation for open built-in function:
从Python标准库文档中提取开放内置函数:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
open(file,mode ='r',buffering = -1,encoding = None,errors = None,newline = None,closefd = True,opener = None)
...file is either a string or bytes object giving the pathname (absolute or relative to the current working directory) of the file to be opened ...
... file是字符串或字节对象,给出要打开的文件的路径名(绝对或相对于当前工作目录)...
Explicitely, open does not bring anything to automagically find a file : if path is not absolute, it is only searched in current directory.
显而易见,open不会带来任何自动查找文件的内容:如果path不是绝对的,则只在当前目录中搜索。
So you will have to use a custom function or a custom class for that. For example:
因此,您必须使用自定义函数或自定义类。例如:
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)
That means that a file opener will keep its own path, will be initialized by default with current path, will have methods to set, append to or extend its path, and will normaly raise a FileNotFoundError is a file is not found in any of the directories listed in its path.
这意味着文件开启器将保留自己的路径,默认情况下将使用当前路径进行初始化,将具有设置,追加或扩展其路径的方法,并且将正常引发FileNotFoundError是在任何文件中找不到的其路径中列出的目录。
Usage :
o = path_opener(['~/.foo-config/', '/usr/local/myapp/foo-config/'])
with o.open('foo') as fd:
...