Python模块:__init__.py如何写入包内非代码文件?
如何写入Python包内的非代码资源文件
你说得没错,pkgutil.get_data()确实只提供了读取包内资源的能力,没办法用来写入文件。这背后其实有合理的设计原因——毕竟Python包安装后,很多时候是放在系统只读目录(比如Linux的/usr/local/lib/pythonX.Y/site-packages),甚至是以压缩包(.egg或.zip)的形式存在,这种情况下根本没法修改包内的文件。
下面是两种可行的思路,优先推荐第一种:
方案一:复制资源到用户可写目录(推荐)
行业惯例是不要直接修改包内的资源文件,而是在程序第一次运行时,把包内的默认资源复制到用户有权限读写的位置(比如用户主目录、应用专属数据目录),之后所有的读写操作都针对这个副本进行。这样既避免了权限问题,也不会因为包更新丢失用户修改的数据。
示例代码:
import pkgutil import os def get_writable_cities_file(): # 1. 读取包内的原始资源 raw_data = pkgutil.get_data("myproject", "resources/cities.txt") if raw_data is None: raise FileNotFoundError("原始资源文件不存在") # 2. 定义用户可写的目标路径(比如用户主目录下的专属文件夹) user_app_dir = os.path.expanduser("~/.myproject") resources_dir = os.path.join(user_app_dir, "resources") # 确保目录存在 os.makedirs(resources_dir, exist_ok=True) target_file = os.path.join(resources_dir, "cities.txt") # 3. 第一次运行时复制原始资源到目标路径 if not os.path.exists(target_file): with open(target_file, "wb") as f: f.write(raw_data) return target_file # 使用示例:写入新内容 file_path = get_writable_cities_file() with open(file_path, "a", encoding="utf-8") as f: f.write("\nNew York")
方案二:直接写入包内文件(仅开发场景使用)
如果你只是在本地开发环境(比如用pip install -e .安装的可编辑包),且包是以解压的文件结构存在(不是压缩包),可以通过定位包的实际路径来写入文件。但这个方法在生产环境几乎不可用,因为会遇到权限问题或包结构限制。
示例代码:
import os # 导入你的包,通过__file__属性获取包的根目录 from myproject import __file__ as package_init_path # 计算资源文件的实际路径 package_root = os.path.dirname(package_init_path) resource_file_path = os.path.join(package_root, "resources", "cities.txt") # 写入文件(仅开发环境测试用) with open(resource_file_path, "a", encoding="utf-8") as f: f.write("\nLos Angeles")
注意事项
- 生产环境绝对不要用方案二,因为普通用户通常没有修改系统site-packages目录的权限,而且包更新时会覆盖你修改的内容。
- 方案一中的用户目录可以根据不同系统调整,比如Windows下可以用
os.environ.get('APPDATA'),macOS用os.path.expanduser("~/Library/Application Support/myproject")。
内容的提问来源于stack exchange,提问作者Quasar
相关产品推荐
相关产品推荐

