我有一个Python脚本,需要一些存储在一个文件中的数据,该文件始终与脚本位于同一位置。我有一个setup.py
脚本,我想确保它的pip可以在各种环境中安装,并且可以在必要时变成独立的可执行文件。
目前该脚本使用Python 2.7和Python 3.3或更高版本运行(虽然我没有3.3的测试环境,因此我无法确定)。
我想出了这种获取数据的方法。这个脚本不是__init__.py
或任何东西的模块目录的一部分,它只是一个独立的文件,如果只是直接使用python
运行,但也有一个在setup.py
文件中定义的入口点。这是一个文件。这是正确的方法吗?
def fetch_wordlist():
wordlist = 'wordlist.txt'
try:
import importlib.resources as res
return res.read_binary(__file__, wordlist)
except ImportError:
pass
try:
import pkg_resources as resources
req = resources.Requirement.parse('makepw')
wordlist = resources.resource_filename(req, wordlist)
except ImportError:
import os.path
wordlist = os.path.join(os.path.dirname(__file__), wordlist)
with open(wordlist, 'rb') as f:
return f.read()
这看起来非常复杂。此外,它似乎依赖于包管理系统我感到不舒服。除非经过pip安装,否则该脚本不再有效,这似乎也不合适。
读取python脚本旁边的文件的标准方法是:
a)如果你有python> = 3.4我建议你使用pathlib模块,如下所示:
from pathlib import Path
def fetch_wordlist(filename="wordlist.txt"):
return (Path(__file__).parent / filename).read_text()
if __name__ == '__main__':
print(fetch_wordlist())
b)如果你仍然使用python版本<3.4或者你仍然想要使用旧的os.path模块,你应该做这样的事情:
import os
def fetch_wordlist(filename="wordlist.txt"):
with open(os.path.join(os.path.dirname(__file__), filename)) as f:
return f.read()
if __name__ == '__main__':
print(fetch_wordlist())
另外,我建议你在外部调用者中捕获异常,上面的方法是在python中读取文件的标准方法,所以你不需要将它们包装在像fetch_wordlist
这样的函数中,否则说,在python中读取文件是一个“原子” “操作。
现在,你可能会使用cx_freeze
,pyinstaller
或similars这样的冰箱冻结你的程序...在这种情况下你需要检测它,这是一个简单的检查方法:
a)使用os.path
:
if getattr(sys, 'frozen', False):
app_path = os.path.dirname(sys.executable)
elif __file__:
app_path = os.path.dirname(__file__)
b)使用pathlib
:
if getattr(sys, 'frozen', False):
app_path = Path(sys.executable).parent
elif __file__:
app_path = Path(__file__).parent
如果代码存在于文件系统上,上述解决方案将起作用,但如果软件包存在于zip文件中则不起作用,当发生这种情况时,您可以使用importlib.resources(3.7版中的新版本)或pkg_resources combo已经在问题中显示(或者你可以结束一些帮助)或者你可以使用一个名为importlib_resources
的漂亮的第三方库,它应该与旧的和现代的python版本一起使用:
特别针对您的特定问题,我建议您看看这个https://importlib-resources.readthedocs.io/en/latest/。
如果你想知道那个库在窗帘后面做了什么,因为你不愿意安装任何第三方库,你可以找到py2 https://importlib-resources.readthedocs.io/en/latest/using.html#file-system-or-zip-file和py3 here的代码,以防你想获得特定问题的相关位
我要走出困境并做出假设,因为它可能会大大简化您的问题。我可以想象你可以声称这些数据“存储在一个始终与脚本位于同一位置的文件中”的唯一方法是因为你创建了这个数据一次,然后把它放在源代码的一个文件中目录。即使这个数据是二进制的,你是否考虑过将数据作为python文件中的文字字节串,然后像其他任何东西一样简单地导入它?
你的阅读文件的方法有点不必要地复杂,这是正确的。除非你有一个非常具体的理由使用here和importlib
模块,否则它很简单。
pkg_resources
您没有提供有关您的脚本的大量信息,因此除非使用import os
def fetch_wordlist():
if not os.path.exists('wordlist.txt'):
raise FileNotFoundError
with open('wordlist.txt', 'rb') as wordlist:
return wordlist.read()
安装,否则我无法评论为什么它不起作用。我最好的猜测:你的脚本可能已经打包成python包。