这是获取与Python脚本相邻/打包的数据的批准方式吗?

问题描述 投票:7回答:3

我有一个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 resources packaging
3个回答
7
投票

生活在文件系统上的资源

读取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_freezepyinstallersimilars这样的冰箱冻结你的程序...在这种情况下你需要检测它,这是一个简单的检查方法:

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文件中的资源

如果代码存在于文件系统上,上述解决方案将起作用,但如果软件包存在于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的代码,以防你想获得特定问题的相关位


5
投票

我要走出困境并做出假设,因为它可能会大大简化您的问题。我可以想象你可以声称这些数据“存储在一个始终与脚本位于同一位置的文件中”的唯一方法是因为你创建了这个数据一次,然后把它放在源代码的一个文件中目录。即使这个数据是二进制的,你是否考虑过将数据作为python文件中的文字字节串,然后像其他任何东西一样简单地导入它?


0
投票

你的阅读文件的方法有点不必要地复杂,这是正确的。除非你有一个非常具体的理由使用hereimportlib模块,否则它很简单。

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包。

© www.soinside.com 2019 - 2024. All rights reserved.