问题
你的包中包含代码需要去读取的数据文件。你需要尽可能地用最便捷的方式来做 这件事。
解决方案
假设你的包中的文件组织成如下:
mypackage/ __init__.py somedata.dat spam.py
现在假设 spam.py 文件需要读取 somedata.dat 文件中的内容。你可以用以下代码 来完成:
# spam.py import pkgutil data = pkgutil.get_data(__package__, 'somedata.dat')
由此产生的变量是包含该文件的原始内容的字节字符串。
要读取数据文件,你可能会倾向于编写使用内置的 I/ O 功能的代码,如 open()。 但是这种方法也有一些问题。
首先,一个包对解释器的当前工作目录几乎没有控制权。因此,编程时任何 I/O 操 作都必须使用绝对文件名。由于每个模块包含有完整路径的 file 变量,这弄清楚 它的路径不是不可能,但它很凌乱。
第二,包通常安装作为.zip 或.egg 文件,这些文件并不像在文件系统上的一个普通 目录里那样被保存。因此,你试图用 open() 对一个包含数据文件的归档文件进行操作, 它根本不会工作。
pkgutil.get_data() 函数是一个读取数据文件的高级工具,不用管包是如何安装以 及安装在哪。它只是工作并将文件内容以字节字符串返回给你get_data() 的第一个参数是包含包名的字符串。你可以直接使用包名,也可以使 用特殊的变量,比如 package。第二个参数是包内文件的相对名称。如果有必要, 可以使用标准的 Unix 命名规范到不同的目录,只有最后的目录仍然位于包中。
>>> import imp >>> imp.reload(spam) <module 'spam' from './spam.py'> >>> spam.bar() bar >>> grok() # Notice old output grok >>> spam.grok() # Notice new output
重新加载模块在开发和调试过程中常常很有用。但在生产环境中的代码使用会不 安全,因为它并不总是像您期望的那样工作。
reload() 擦除了模块底层字典的内容,并通过重新执行模块的源代码来刷新它。模 块对象本身的身份保持不变。因此,该操作在程序中所有已经被导入了的地方更新了模 块。
尽管如此,reload() 没有更新像”from module import name”这样使用 import 语 句导入的定义。