这是通过 Python 脚本访问 to/packaged 附近数据的批准方式吗?
Is this the approved way to acess data adjacent to/packaged with a Python script?
我有一个 Python 脚本需要一些数据存储在一个文件中,该文件始终与脚本位于同一位置。我有一个用于脚本的 setup.py
,我想确保它可以在各种环境中通过 pip 安装,并且可以在必要时转换为独立的可执行文件。
目前 运行s 的脚本 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 安装的,而且这似乎也不可取。
您说得对,您读取文件的方法有点不必要地复杂。除非您有真正特定的理由使用 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()
您没有提供太多关于您的脚本的信息,所以我不能评论为什么它不能工作,除非它是使用 pip
安装的。我的最佳猜测:您的脚本可能打包到 python 包中。
文件系统中的资源
读取与 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 中文件的标准方法,因此您不需要将它们包装在 [=14= 之类的函数中],否则的话,读取python中的文件是一个"atomic"操作。
现在,您可能会使用 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 (new in version 3.7) or pkg_resources 组合,因为已经在问题中展示了(或者你可以用一些助手来解决)或者你可以使用一个很好的第三方库 importlib_resources
应该与旧的和现代的 python 版本一起工作:
- pypi: https://pypi.org/project/importlib_resources/
- 文档:https://importlib-resources.readthedocs.io/en/latest/
特别针对您的特定问题,我建议您看看这个 https://importlib-resources.readthedocs.io/en/latest/using.html#file-system-or-zip-file。
如果您想知道该库在幕后做了什么,因为您不愿意安装任何第 3 方库,您可以找到 py2 here and py3 here 的代码,以防您想要获得相关信息针对您的特定问题的位
我要冒险做一个假设,因为它可能会大大简化您的问题。我可以想象的唯一方式,你可以声称这个数据是 "stored in a file that will always be in the same location as the script" 是因为你创建了这个数据,一次,并将它放在源代码目录中的一个文件中。即使此数据是二进制数据,您是否考虑过将数据作为 python 文件中的文字字节字符串,然后像导入其他任何东西一样简单地导入它?
我有一个 Python 脚本需要一些数据存储在一个文件中,该文件始终与脚本位于同一位置。我有一个用于脚本的 setup.py
,我想确保它可以在各种环境中通过 pip 安装,并且可以在必要时转换为独立的可执行文件。
目前 运行s 的脚本 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 安装的,而且这似乎也不可取。
您说得对,您读取文件的方法有点不必要地复杂。除非您有真正特定的理由使用 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()
您没有提供太多关于您的脚本的信息,所以我不能评论为什么它不能工作,除非它是使用 pip
安装的。我的最佳猜测:您的脚本可能打包到 python 包中。
文件系统中的资源
读取与 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 中文件的标准方法,因此您不需要将它们包装在 [=14= 之类的函数中],否则的话,读取python中的文件是一个"atomic"操作。
现在,您可能会使用 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 (new in version 3.7) or pkg_resources 组合,因为已经在问题中展示了(或者你可以用一些助手来解决)或者你可以使用一个很好的第三方库 importlib_resources
应该与旧的和现代的 python 版本一起工作:
- pypi: https://pypi.org/project/importlib_resources/
- 文档:https://importlib-resources.readthedocs.io/en/latest/
特别针对您的特定问题,我建议您看看这个 https://importlib-resources.readthedocs.io/en/latest/using.html#file-system-or-zip-file。
如果您想知道该库在幕后做了什么,因为您不愿意安装任何第 3 方库,您可以找到 py2 here and py3 here 的代码,以防您想要获得相关信息针对您的特定问题的位
我要冒险做一个假设,因为它可能会大大简化您的问题。我可以想象的唯一方式,你可以声称这个数据是 "stored in a file that will always be in the same location as the script" 是因为你创建了这个数据,一次,并将它放在源代码目录中的一个文件中。即使此数据是二进制数据,您是否考虑过将数据作为 python 文件中的文字字节字符串,然后像导入其他任何东西一样简单地导入它?