240 lines
6.0 KiB
Markdown
240 lines
6.0 KiB
Markdown
# `ExecFile.py` 技术文档
|
||
|
||
```markdown
|
||
# ExecFile.py - 动态执行 Python 配置文件并构建配置对象
|
||
|
||
`ExecFile.py` 是一个轻量级的 Python 模块,用于从 `.py` 或 `.ini` 类似格式的文本文件中动态加载配置数据。它通过 `exec()` 执行文件内容,并将变量注入指定命名空间,支持嵌套字典自动转换为可属性访问的对象。
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
该模块主要包含两个核心类:
|
||
|
||
- `DictConfig`: 一个增强型字典类,允许通过属性语法访问键值,并支持嵌套结构递归转换。
|
||
- `ExecFile`: 提供运行外部配置文件的能力,可设置变量、执行脚本并获取结果。
|
||
|
||
典型应用场景包括:
|
||
- 加载可编程的配置文件(如卡片配置、游戏规则等)
|
||
- 实现插件式配置系统
|
||
- 将 Python 脚本作为配置源使用
|
||
|
||
---
|
||
|
||
## 安装与导入
|
||
|
||
无需安装,直接将 `ExecFile.py` 放入项目路径后导入即可:
|
||
|
||
```python
|
||
from ExecFile import ExecFile, DictConfig
|
||
```
|
||
|
||
---
|
||
|
||
## 核心类说明
|
||
|
||
### 1. `DictConfig(dic=None, path=None, str=None, namespace={})`
|
||
|
||
一个支持属性访问和嵌套结构解析的字典类。
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 类型 | 描述 |
|
||
|------|------|------|
|
||
| `dic` | `dict` | 初始字典数据,会被深度转换为 `DictConfig` 对象 |
|
||
| `path` | `str` | 配置文件路径,自动读取并执行其中的 Python 代码 |
|
||
| `str` | `str` | 包含 Python 代码的字符串,将在指定命名空间中执行 |
|
||
| `namespace` | `dict` | 执行代码时使用的全局命名空间 |
|
||
|
||
> ⚠️ 注意:`path` 和 `str` 不能同时为 `None`;若提供多个参数,则按顺序依次处理。
|
||
|
||
#### 属性与方法
|
||
|
||
##### `.keys()`
|
||
返回所有键名。
|
||
|
||
##### `.__getitem__(key)`
|
||
支持 `obj[key]` 访问方式。
|
||
|
||
##### `.__getattr__(name)`
|
||
支持 `obj.name` 属性式访问。如果属性不存在则抛出 `AttributeError`。
|
||
|
||
##### `.__subConfig()`
|
||
私有方法:递归遍历字典中的结构化数据(`dict`, `list`, `tuple`),将其中的 `dict` 自动转为 `DictConfig` 实例,实现链式属性访问。
|
||
|
||
例如:
|
||
```python
|
||
data = {'user': {'name': 'Alice', 'age': 30}}
|
||
config = DictConfig(dic=data)
|
||
print(config.user.name) # 输出: Alice
|
||
```
|
||
|
||
##### `.__load(path)`
|
||
私有方法:从文件路径加载内容并执行,提取变量到当前实例。
|
||
|
||
---
|
||
|
||
### 2. `ExecFile(obj=None, path=None, namespace={})`
|
||
|
||
用于执行外部 Python 风格配置文件的核心类。
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 类型 | 描述 |
|
||
|------|------|------|
|
||
| `obj` | `object` | 目标对象,配置变量将被注入此对象的 `__dict__` 中。默认为 `self` |
|
||
| `path` | `str` | 要执行的配置文件路径(可选) |
|
||
| `namespace` | `dict` | 全局命名空间(目前未完全启用) |
|
||
|
||
#### 方法
|
||
|
||
##### `.set(name, v)`
|
||
设置目标对象的一个属性。
|
||
|
||
**参数:**
|
||
- `name` (str): 属性名
|
||
- `v`: 属性值
|
||
|
||
**示例:**
|
||
```python
|
||
r = ExecFile()
|
||
r.set('game_mode', 'hard')
|
||
```
|
||
|
||
##### `.get(name, default=None)`
|
||
获取目标对象的属性值,若不存在返回默认值。
|
||
|
||
**参数:**
|
||
- `name` (str): 属性名
|
||
- `default`: 默认返回值
|
||
|
||
**示例:**
|
||
```python
|
||
mode = r.get('game_mode', 'normal')
|
||
```
|
||
|
||
##### `.run(path=None)`
|
||
执行指定路径的配置文件。
|
||
|
||
**参数:**
|
||
- `path` (str): 配置文件路径。若传入则更新内部路径记录。
|
||
|
||
**返回值:**
|
||
- 成功时返回 `(True, '')`
|
||
- 失败时返回 `(False, Exception)` 并打印错误信息
|
||
|
||
**行为说明:**
|
||
- 使用 `open()` 读取文件内容
|
||
- 通过 `exec(buf, globals(), self.__object.__dict__)` 执行代码,变量注入目标对象
|
||
- 若文件路径未设置且未传参,则抛出异常
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 示例 1:基本用法 —— 加载配置文件
|
||
|
||
假设有一个配置文件 `test/cards.ini` 内容如下:
|
||
|
||
```python
|
||
# test/cards.ini
|
||
cards = [
|
||
{'id': 1, 'name': 'Fireball', 'damage': 50},
|
||
{'id': 2, 'name': 'Shield', 'damage': 0}
|
||
]
|
||
game_version = "1.0.0"
|
||
max_players = 4
|
||
```
|
||
|
||
使用 `ExecFile` 加载:
|
||
|
||
```python
|
||
r = ExecFile()
|
||
r.run('test/cards.ini')
|
||
|
||
# 访问配置项
|
||
print(r.cards[0]['name']) # 输出: Fireball
|
||
print(r.game_version) # 输出: 1.0.0
|
||
print(r.max_players) # 输出: 4
|
||
```
|
||
|
||
### 示例 2:预设变量 + 执行文件
|
||
|
||
```python
|
||
r = ExecFile()
|
||
r.set('player_level', 5)
|
||
r.run('test/cards.ini')
|
||
|
||
# 在 cards.ini 中可以引用 player_level 变量
|
||
# 例如:bonus_damage = player_level * 10
|
||
```
|
||
|
||
### 示例 3:结合 DictConfig 解析嵌套结构
|
||
|
||
```python
|
||
config_str = """
|
||
user = {
|
||
'profile': {
|
||
'name': 'Bob',
|
||
'settings': ['dark_mode', 'notifications']
|
||
}
|
||
}
|
||
"""
|
||
|
||
dc = DictConfig(str=config_str)
|
||
print(dc.user.profile.name) # 输出: Bob
|
||
print(dc.user.profile.settings) # 输出: ['dark_mode', 'notifications']
|
||
```
|
||
|
||
---
|
||
|
||
## 文件格式要求
|
||
|
||
配置文件应为合法的 Python 语法片段,常见形式包括:
|
||
|
||
- 变量赋值:`var = value`
|
||
- 字典定义:`config = {'key': 'value'}`
|
||
- 列表/元组:`items = [1, 2, 3]`
|
||
- 支持表达式计算(依赖已定义变量)
|
||
|
||
⚠️ **安全警告**:由于使用了 `exec()`,请确保配置文件来源可信,避免远程或用户上传执行。
|
||
|
||
---
|
||
|
||
## 错误处理
|
||
|
||
- `run()` 方法捕获所有异常并输出错误日志:
|
||
```
|
||
ExecFile() <Exception Message> <FilePath>
|
||
```
|
||
- 返回 `(False, exception)` 表示执行失败,调用者应进行相应处理。
|
||
|
||
---
|
||
|
||
## 已知限制
|
||
|
||
1. 不支持异步文件读取
|
||
2. `__load()` 方法在 `DictConfig` 中存在但未被公开调用接口
|
||
3. 命名空间机制较简单,`globals()` 被直接传递
|
||
4. 异常处理较为基础,仅打印信息无重试机制
|
||
|
||
---
|
||
|
||
## 版本信息
|
||
|
||
- 创建时间:未知
|
||
- 作者:未知
|
||
- 语言版本:Python 2/3 兼容(建议 Python 3.x)
|
||
|
||
> 注:代码中使用了 `print` 函数兼容写法,适用于 Python 3。
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
`ExecFile.py` 提供了一种灵活的方式来加载“代码即配置”的 `.py` 或 `.ini` 风格文件,适合小型项目或需要动态逻辑配置的场景。配合 `DictConfig` 可实现优雅的嵌套配置访问。
|
||
|
||
推荐在受控环境中使用,注意安全风险。
|
||
|
||
---
|
||
``` |