gaskill 2.15.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. gaskill/__init__.py +13 -0
  2. gaskill/gaskill/__init__.py +28 -0
  3. gaskill/gaskill/_roll.py +169 -0
  4. gaskill/gaskill/abc.py +73 -0
  5. gaskill/gaskill/builtins_plus.py +73 -0
  6. gaskill/gaskill/pickle.py +318 -0
  7. gaskill/gaskill/sbase64.py +287 -0
  8. gaskill/gaskill/scache.py +448 -0
  9. gaskill/gaskill/scolor.py +388 -0
  10. gaskill/gaskill/scrypt.py +209 -0
  11. gaskill/gaskill/scurve.py +387 -0
  12. gaskill/gaskill/seasing.py +259 -0
  13. gaskill/gaskill/sevent.py +218 -0
  14. gaskill/gaskill/sformat.py +591 -0
  15. gaskill/gaskill/sfrac.py +403 -0
  16. gaskill/gaskill/sfsm.py +209 -0
  17. gaskill/gaskill/sgeometry.py +790 -0
  18. gaskill/gaskill/sgeometry3d.py +371 -0
  19. gaskill/gaskill/sinterp.py +168 -0
  20. gaskill/gaskill/smath.py +1111 -0
  21. gaskill/gaskill/smatrix.py +605 -0
  22. gaskill/gaskill/snoise.py +305 -0
  23. gaskill/gaskill/solver.py +176 -0
  24. gaskill/gaskill/spathfinder.py +547 -0
  25. gaskill/gaskill/spool.py +201 -0
  26. gaskill/gaskill/squaternion.py +439 -0
  27. gaskill/gaskill/srandom.py +280 -0
  28. gaskill/gaskill/ssaver.py +303 -0
  29. gaskill/gaskill/sstat.py +463 -0
  30. gaskill/gaskill/sui.py +474 -0
  31. gaskill/gaskill/svector.py +756 -0
  32. gaskill/gaskill/type.py +133 -0
  33. gaskill/plus/__init__.py +12 -0
  34. gaskill/plus/bmp.py +436 -0
  35. gaskill/plus/database.py +174 -0
  36. gaskill/plus/decimal.py +462 -0
  37. gaskill/plus/ecc.py +160 -0
  38. gaskill/plus/hashlib.py +185 -0
  39. gaskill/plus/pickle.py +320 -0
  40. gaskill/plus/poly.py +426 -0
  41. gaskill/plus/radical.py +608 -0
  42. gaskill/plus/re.py +511 -0
  43. gaskill/plus/tester.py +500 -0
  44. gaskill/plus/tree.py +180 -0
  45. gaskill/plus/zip.py +233 -0
  46. gaskill/test/__init__.py +6 -0
  47. gaskill/test/test_all.py +11 -0
  48. gaskill/test/test_decimal.py +656 -0
  49. gaskill/test/test_frac.py +487 -0
  50. gaskill/test/test_radical.py +243 -0
  51. gaskill/test/test_saver.py +152 -0
  52. gaskill/test/test_smath.py +321 -0
  53. gaskill-2.15.2.dist-info/METADATA +43 -0
  54. gaskill-2.15.2.dist-info/RECORD +57 -0
  55. gaskill-2.15.2.dist-info/WHEEL +5 -0
  56. gaskill-2.15.2.dist-info/licenses/LICENSE +21 -0
  57. gaskill-2.15.2.dist-info/top_level.txt +1 -0
gaskill/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ # ruff: noqa: F403
2
+ from .gaskill import *
3
+ from .plus import *
4
+ print(r"""
5
+ _ _ _
6
+ _ __ ___ | (_) |__
7
+ | '_ ` _ \| | | '_ \
8
+ | | | | | | | | |_) |
9
+ |_| |_| |_|_|_|_.__/ """)
10
+ print("Hello from mlib. It isn't a serious library. Welcome to raise PRs. If you want to know the rules, please see PRlicense.")
11
+ __PRlicense__ = "Do not use any C or Rust extensions, and ensure neither exists in the dependency tree."
12
+ __license__ = "MIT"
13
+ __author__ = "everyone"
@@ -0,0 +1,28 @@
1
+ # ruff: noqa: F403
2
+ from .smath import *
3
+ from .sfrac import *
4
+ from .svector import *
5
+ from .smatrix import *
6
+ from .squaternion import *
7
+ from .srandom import *
8
+ from .scolor import *
9
+ from .sgeometry import *
10
+ from .sgeometry3d import *
11
+ from .scurve import *
12
+ from .seasing import *
13
+ from .sinterp import *
14
+ from .scache import *
15
+ from .sevent import *
16
+ from .sfsm import *
17
+ from .spool import *
18
+ from .spathfinder import *
19
+ from .ssaver import *
20
+ from .sui import *
21
+ from .sformat import *
22
+ from .snoise import *
23
+ from .scrypt import *
24
+ from .solver import *
25
+ from .sstat import *
26
+ from .sbase64 import *
27
+ from .abc import *
28
+ from .pickle import *
@@ -0,0 +1,169 @@
1
+ def parse_dice(expr):
2
+ expr = expr.replace(' ', '')
3
+
4
+ # 按加减号分割表达式
5
+ parts = _split_expression(expr)
6
+
7
+ result = {
8
+ 'expr': expr,
9
+ 'parts': [],
10
+ 'total': 0
11
+ }
12
+
13
+ for part in parts:
14
+ if 'd' in part.lower():
15
+ part_result = _parse_single_dice(part)
16
+ else:
17
+ part_result = _parse_number(part)
18
+
19
+ result['parts'].append(part_result)
20
+ result['total'] += part_result['value']
21
+
22
+ return result
23
+
24
+
25
+ def _split_expression(expr):
26
+ parts = []
27
+ current = ''
28
+
29
+ for i, char in enumerate(expr):
30
+ if char in '+-' and i > 0:
31
+ parts.append(current)
32
+ current = char
33
+ else:
34
+ current += char
35
+
36
+ if current:
37
+ parts.append(current)
38
+
39
+ return parts
40
+
41
+
42
+ def _parse_single_dice(expr):
43
+ d_pos = expr.lower().find('d')
44
+
45
+ # 解析骰子数量
46
+ count_str = expr[:d_pos]
47
+ count = int(count_str) if count_str else 1
48
+
49
+ # 解析剩余部分
50
+ rest = expr[d_pos+1:]
51
+
52
+ # 初始化结果
53
+ result = {
54
+ 'expr': expr,
55
+ 'type': 'dice',
56
+ 'count': count,
57
+ 'sides': 0,
58
+ 'modifier': None,
59
+ 'modifier_value': 0,
60
+ 'explode': None,
61
+ 'bonus': 0,
62
+ 'value': 0 # 占位,实际掷骰时计算
63
+ }
64
+
65
+ i = 0
66
+ # 读骰子面数
67
+ sides_str = ''
68
+ while i < len(rest) and rest[i].isdigit():
69
+ sides_str += rest[i]
70
+ i += 1
71
+
72
+ result['sides'] = int(sides_str)
73
+
74
+ # 读修饰符
75
+ if i < len(rest) and rest[i].isalpha():
76
+ mod = rest[i]
77
+ i += 1
78
+ if i < len(rest) and rest[i].isalpha():
79
+ mod += rest[i]
80
+ i += 1
81
+ result['modifier'] = mod
82
+
83
+ # 读修饰符数值
84
+ mod_val_str = ''
85
+ while i < len(rest) and rest[i].isdigit():
86
+ mod_val_str += rest[i]
87
+ i += 1
88
+ result['modifier_value'] = int(mod_val_str) if mod_val_str else 1
89
+
90
+ # 读爆炸骰
91
+ if i < len(rest) and rest[i] == 'x':
92
+ i += 1
93
+ explode_str = ''
94
+ while i < len(rest) and rest[i].isdigit():
95
+ explode_str += rest[i]
96
+ i += 1
97
+ result['explode'] = int(explode_str)
98
+
99
+ # 读加减
100
+ if i < len(rest) and rest[i] in '+-':
101
+ result['bonus'] = int(rest[i:])
102
+
103
+ return result
104
+
105
+
106
+ def _parse_number(expr):
107
+ return {
108
+ 'expr': expr,
109
+ 'type': 'number',
110
+ 'value': int(expr)
111
+ }
112
+
113
+
114
+ def roll_dice(parse_result, random_func):
115
+ if parse_result['type'] == 'number':
116
+ return parse_result['value']
117
+
118
+ # 先掷出所有骰子
119
+ rolls = [random_func(1, parse_result['sides'])
120
+ for _ in range(parse_result['count'])]
121
+
122
+ # 应用爆炸骰
123
+ if parse_result['explode']:
124
+ rolls = _apply_explode(rolls, parse_result['sides'],
125
+ parse_result['explode'], random_func)
126
+
127
+ # 应用修饰符
128
+ if parse_result['modifier'] == 'kh':
129
+ rolls = sorted(rolls, reverse=True)[:parse_result['modifier_value']]
130
+ elif parse_result['modifier'] == 'kl':
131
+ rolls = sorted(rolls)[:parse_result['modifier_value']]
132
+ elif parse_result['modifier'] == 'd':
133
+ rolls = sorted(rolls)[parse_result['modifier_value']:]
134
+
135
+ return sum(rolls) + parse_result['bonus']
136
+
137
+
138
+ def _apply_explode(rolls, sides, target, random_func):
139
+ """递归应用爆炸骰"""
140
+ result = rolls.copy()
141
+ for roll in rolls:
142
+ if roll == target:
143
+ extra = random_func(1, sides)
144
+ result.append(extra)
145
+ if extra == target: # 递归爆炸
146
+ result.extend(_apply_explode([extra], sides, target, random_func))
147
+ return result
148
+
149
+
150
+ def get_dice_info(expr):
151
+ result = parse_dice(expr)
152
+ info = {
153
+ 'expr': expr,
154
+ 'dice_count': 0,
155
+ 'total_sides': 0,
156
+ 'has_modifier': False,
157
+ 'has_explode': False
158
+ }
159
+
160
+ for part in result['parts']:
161
+ if part['type'] == 'dice':
162
+ info['dice_count'] += part['count']
163
+ info['total_sides'] += part['sides'] * part['count']
164
+ if part['modifier']:
165
+ info['has_modifier'] = True
166
+ if part['explode']:
167
+ info['has_explode'] = True
168
+
169
+ return info
gaskill/gaskill/abc.py ADDED
@@ -0,0 +1,73 @@
1
+ """
2
+ gaskill.abc - 抽象基类模块(零依赖)
3
+ """
4
+
5
+
6
+ class ABCMeta(type):
7
+ """元类:自动收集抽象方法"""
8
+
9
+ def __new__(cls, name, bases, dct):
10
+ # 1. 从所有父类继承抽象方法
11
+ abstract_methods = set()
12
+ for base in bases:
13
+ if hasattr(base, '_abstract_methods'):
14
+ abstract_methods.update(base._abstract_methods)
15
+
16
+ # 2. 处理当前类定义的方法
17
+ for key, value in dct.items():
18
+ # 如果当前类显式定义了抽象方法(有 _is_abstract 标记)
19
+ if hasattr(value, '_is_abstract') and value._is_abstract:
20
+ abstract_methods.add(key)
21
+ else:
22
+ # 如果当前类定义了具体实现(没有 _is_abstract 标记)
23
+ # 并且该方法在抽象方法集合中,则移除(即实现了该抽象方法)
24
+ if key in abstract_methods:
25
+ abstract_methods.remove(key)
26
+
27
+ # 3. 存储最终的抽象方法集合
28
+ dct['_abstract_methods'] = frozenset(abstract_methods)
29
+ return super().__new__(cls, name, bases, dct)
30
+
31
+ def __call__(cls, *args, **kwargs):
32
+ """实例化时检查抽象方法是否都已实现"""
33
+ if cls._abstract_methods:
34
+ methods = ', '.join(cls._abstract_methods)
35
+ raise TypeError(
36
+ f"Can't instantiate abstract class {cls.__name__} "
37
+ f"with abstract methods {methods}"
38
+ )
39
+ return super().__call__(*args, **kwargs)
40
+
41
+
42
+ class ABC(metaclass=ABCMeta):
43
+ """抽象基类"""
44
+
45
+ def __init__(self):
46
+
47
+ if type(self) is ABC:
48
+ raise TypeError(
49
+ "Can't instantiate abstract class ABC with abstract methods")
50
+
51
+
52
+ def abstractmethod(func):
53
+ """装饰器:标记抽象方法"""
54
+ func._is_abstract = True
55
+ return func
56
+
57
+
58
+ def abstractclassmethod(func):
59
+ """装饰器:标记抽象类方法"""
60
+ func._is_abstract = True
61
+ return classmethod(func)
62
+
63
+
64
+ def abstractstaticmethod(func):
65
+ """装饰器:标记抽象静态方法"""
66
+ func._is_abstract = True
67
+ return staticmethod(func)
68
+
69
+
70
+ def abstractproperty(func):
71
+ """装饰器:标记抽象属性"""
72
+ func._is_abstract = True
73
+ return property(func)
@@ -0,0 +1,73 @@
1
+ from .abc import ABC, abstractmethod
2
+
3
+
4
+ class Iterable(ABC):
5
+ @abstractmethod
6
+ def __iter__(self):
7
+ while False:
8
+ yield None
9
+
10
+ @classmethod
11
+ def __subclasshook__(cls, C):
12
+ if cls is Iterable:
13
+ if any("__iter__" in B.__dict__ for B in C.__mro__):
14
+ return True
15
+ return NotImplemented
16
+
17
+
18
+ class DefaultDict:
19
+ """带默认值的字典"""
20
+
21
+ def __init__(self, default_factory=None, **kwargs):
22
+ self._data = {}
23
+ self._default_factory = default_factory
24
+ self.update(kwargs)
25
+
26
+ def __getitem__(self, key):
27
+ try:
28
+ return self._data[key]
29
+ except KeyError:
30
+ if self._default_factory is None:
31
+ raise
32
+ value = self._default_factory()
33
+ self._data[key] = value
34
+ return value
35
+
36
+ def __setitem__(self, key, value):
37
+ self._data[key] = value
38
+
39
+ def __delitem__(self, key):
40
+ del self._data[key]
41
+
42
+ def __iter__(self):
43
+ return iter(self._data)
44
+
45
+ def __len__(self):
46
+ return len(self._data)
47
+
48
+ def __repr__(self):
49
+ return f"DefaultDict({self._default_factory}, {self._data})"
50
+
51
+ def update(self, other):
52
+ self._data.update(other)
53
+
54
+ def get(self, key, default=None):
55
+ return self._data.get(key, default)
56
+
57
+ def pop(self, key, default=None):
58
+ return self._data.pop(key, default)
59
+
60
+ def keys(self):
61
+ return self._data.keys()
62
+
63
+ def values(self):
64
+ return self._data.values()
65
+
66
+ def items(self):
67
+ return self._data.items()
68
+
69
+ def copy(self):
70
+ return DefaultDict(self._default_factory, **self._data)
71
+
72
+ def clear(self):
73
+ self._data.clear()
@@ -0,0 +1,318 @@
1
+ def pack_float(num):
2
+ """将浮点数转换为二进制表示"""
3
+
4
+ if num == 0:
5
+ if str(num) == "0.0":
6
+ return '0' * 64
7
+ else:
8
+ return '1' + '0' * 63
9
+
10
+ if num == float("inf") or num == float("-inf"):
11
+ return '0' + '1'*11 + '0'*52 if num > 0 else '1' + '1'*11 + '0'*52
12
+
13
+ if str(num) == 'nan':
14
+ return '0' + '1'*11 + '1' + '0'*51
15
+
16
+ sign = '0' if num > 0 else '1'
17
+ num = abs(num)
18
+
19
+ int_part = int(num)
20
+ frac_part = num - int_part
21
+
22
+ int_bits = []
23
+ if int_part == 0:
24
+ int_bits = ['0']
25
+ else:
26
+ temp = int_part
27
+ while temp > 0:
28
+ int_bits.append(str(temp % 2))
29
+ temp //= 2
30
+ int_bits.reverse()
31
+
32
+ frac_bits = []
33
+ temp = frac_part
34
+ count = 0
35
+ while temp > 0 and count < 60:
36
+ temp *= 2
37
+ if temp >= 1:
38
+ frac_bits.append('1')
39
+ temp -= 1
40
+ else:
41
+ frac_bits.append('0')
42
+ count += 1
43
+ binary = int_bits + frac_bits
44
+
45
+ first_one = -1
46
+ for i, bit in enumerate(binary):
47
+ if bit == '1':
48
+ first_one = i
49
+ break
50
+
51
+ if first_one == -1: # 全是0
52
+ return '0' * 64
53
+
54
+ if first_one < len(int_bits):
55
+ exponent = len(int_bits) - first_one - 1
56
+ else:
57
+ exponent = - (first_one - len(int_bits) + 1)
58
+
59
+ biased_exponent = exponent + 1023
60
+ exp_bits = bin(biased_exponent)[2:].zfill(11)
61
+
62
+ mantissa_start = first_one + 1
63
+ mantissa_bits = binary[mantissa_start:mantissa_start + 52]
64
+
65
+ mantissa_bits = mantissa_bits + ['0'] * (52 - len(mantissa_bits))
66
+ mantissa_bits = ''.join(mantissa_bits[:52])
67
+
68
+ result = sign + exp_bits + mantissa_bits
69
+
70
+ return result
71
+
72
+
73
+ def unpack_float(byte_data):
74
+ """从 8 字节解析 IEEE 754 双精度浮点数(不用 struct)"""
75
+ # 修复:如果传入的是字符串,先转换为字节
76
+ if isinstance(byte_data, str):
77
+ # 将二进制字符串转换为字节
78
+ if len(byte_data) == 64:
79
+ # 每 8 位转一个字节
80
+ byte_list = []
81
+ for i in range(0, 64, 8):
82
+ byte_list.append(int(byte_data[i:i+8], 2))
83
+ byte_data = bytes(byte_list)
84
+ else:
85
+ raise ValueError("二进制字符串长度必须是64")
86
+
87
+ # 1. 转成 64 位二进制字符串
88
+ bits = ''.join(format(b, '08b') for b in byte_data)
89
+
90
+ # 2. 解析符号、指数、尾数
91
+ sign = int(bits[0])
92
+ exponent = int(bits[1:12], 2)
93
+ mantissa = int(bits[12:], 2)
94
+
95
+ # 3. 特殊值
96
+ if exponent == 2047:
97
+ if mantissa == 0:
98
+ return float('-inf') if sign else float('inf')
99
+ return float('nan')
100
+
101
+ # 4. 零
102
+ if exponent == 0 and mantissa == 0:
103
+ return -0.0 if sign else 0.0
104
+
105
+ # 5. 非规格化数
106
+ if exponent == 0:
107
+ value = (mantissa / (2**52)) * (2 ** -1022)
108
+ return -value if sign else value
109
+
110
+ # 6. 规格化数
111
+ value = (1 + mantissa / (2**52)) * (2 ** (exponent - 1023))
112
+ return -value if sign else value
113
+
114
+
115
+ def pack_int(n, bits=None):
116
+ if bits is None:
117
+ # 自动计算所需位数(包括符号位)
118
+ if n >= 0:
119
+ bits = max(1, n.bit_length() + 1)
120
+ else:
121
+ bits = max(1, (-n).bit_length() + 1)
122
+
123
+ if n < 0:
124
+ n = (1 << bits) + n
125
+
126
+ return bin(n)[2:].zfill(bits)[-bits:]
127
+
128
+
129
+ def pack_str(n):
130
+ from .smath import ceil
131
+ result = bin(int.from_bytes(n.encode(), "big"))[2:]
132
+ return result.rjust(ceil(len(result) / 8) * 8, "0")
133
+
134
+
135
+ def bits_to_bytes(bits):
136
+ """二进制字符串 → bytes"""
137
+ # 补齐到 8 的倍数
138
+ if len(bits) % 8 != 0:
139
+ bits = bits.rjust((len(bits) + 7) // 8 * 8, "0")
140
+
141
+ # 每 8 位转一个字节
142
+ result = []
143
+ for i in range(0, len(bits), 8):
144
+ result.append(int(bits[i:i+8], 2))
145
+ return bytes(result)
146
+
147
+
148
+ def bytes_to_bits(data):
149
+ """bytes → 二进制字符串"""
150
+ return ''.join(format(b, '08b') for b in data)
151
+
152
+
153
+ def pack_to_file(obj, filename):
154
+ """打包对象并写入文件"""
155
+ # 1. 打包对象
156
+ packed = pack(obj) # 返回 b'类型标记 + 二进制字符串 + \x00'
157
+
158
+ # 2. 写入文件
159
+ with open(filename, 'wb') as f:
160
+ f.write(packed)
161
+
162
+
163
+ # ============ 辅助函数 ============
164
+
165
+ def pack_varint(n):
166
+ """变长整数编码(无符号)"""
167
+ if n == 0:
168
+ return b'\x00'
169
+ result = []
170
+ while n > 0:
171
+ byte = n & 0x7F
172
+ n >>= 7
173
+ if n > 0:
174
+ byte |= 0x80
175
+ result.append(byte)
176
+ return bytes(result)
177
+
178
+
179
+ def unpack_varint(data, pos):
180
+ """解包变长整数"""
181
+ result = 0
182
+ shift = 0
183
+ while pos < len(data):
184
+ byte = data[pos]
185
+ pos += 1
186
+ result |= (byte & 0x7F) << shift
187
+ if not (byte & 0x80):
188
+ return result, pos
189
+ shift += 7
190
+ raise ValueError("不完整的变长整数")
191
+
192
+
193
+ # ============ pack ============
194
+
195
+ def pack(obj):
196
+ """打包任意对象为二进制"""
197
+ if isinstance(obj, str):
198
+ # 字符串:S + 变长长度 + UTF-8 数据
199
+ data = obj.encode('utf-8')
200
+ return b'S' + pack_varint(len(data)) + data
201
+
202
+ elif isinstance(obj, int):
203
+ # 整数:I + 变长编码
204
+ if obj >= 0:
205
+ return b'I' + pack_varint(obj)
206
+ else:
207
+ # 负数用补码
208
+ return b'i' + pack_varint(-obj)
209
+
210
+ elif isinstance(obj, float):
211
+ # 浮点数:F + 8字节 IEEE 754
212
+ bits = pack_float(obj) # 您的函数,返回二进制字符串
213
+ return b'F' + bits_to_bytes(bits)
214
+
215
+ elif isinstance(obj, bool):
216
+ # 布尔值:B + 1字节 (0 或 1)
217
+ return b'B' + (b'\x01' if obj else b'\x00')
218
+
219
+ elif isinstance(obj, (list, tuple)):
220
+ # 列表:L + 每个元素递归 + E
221
+ result = b'L'
222
+ for item in obj:
223
+ result += pack(item)
224
+ return result + b'E'
225
+
226
+ elif isinstance(obj, dict):
227
+ # 字典:D + 每个键值对递归 + E
228
+ result = b'D'
229
+ for key, value in obj.items():
230
+ result += pack(key) + pack(value)
231
+ return result + b'E'
232
+
233
+ elif obj is None:
234
+ # None:N
235
+ return b'N'
236
+
237
+ else:
238
+ raise TypeError(f"不支持的类型: {type(obj)}")
239
+
240
+
241
+ # ============ unpack ============
242
+
243
+ def unpack(data, pos=0):
244
+ """从二进制解包"""
245
+ if pos >= len(data):
246
+ return None, pos
247
+
248
+ type_code = data[pos:pos+1]
249
+ pos += 1
250
+
251
+ if type_code == b'S':
252
+ # 字符串
253
+ length, pos = unpack_varint(data, pos)
254
+ value = data[pos:pos+length].decode('utf-8')
255
+ return value, pos + length
256
+
257
+ elif type_code == b'I':
258
+ # 无符号整数
259
+ value, pos = unpack_varint(data, pos)
260
+ return value, pos
261
+
262
+ elif type_code == b'i':
263
+ # 负整数
264
+ value, pos = unpack_varint(data, pos)
265
+ return -value, pos
266
+
267
+ elif type_code == b'F':
268
+ # 浮点数 - 直接传入字节数据
269
+ value = unpack_float(data[pos:pos+8])
270
+ return value, pos + 8
271
+
272
+ elif type_code == b'B':
273
+ # 布尔值
274
+ value = data[pos] == 1
275
+ return value, pos + 1
276
+
277
+ elif type_code == b'L':
278
+ # 列表
279
+ result = []
280
+ while pos < len(data):
281
+ if data[pos:pos+1] == b'E':
282
+ pos += 1
283
+ break
284
+ item, pos = unpack(data, pos)
285
+ result.append(item)
286
+ return result, pos
287
+
288
+ elif type_code == b'D':
289
+ # 字典
290
+ result = {}
291
+ while pos < len(data):
292
+ if data[pos:pos+1] == b'E':
293
+ pos += 1
294
+ break
295
+ key, pos = unpack(data, pos)
296
+ value, pos = unpack(data, pos)
297
+ result[key] = value
298
+ return result, pos
299
+
300
+ elif type_code == b'N':
301
+ # None
302
+ return None, pos
303
+
304
+ else:
305
+ raise TypeError(f"未知类型码: {type_code}")
306
+
307
+
308
+ def dump(obj, filename):
309
+ """保存对象到文件"""
310
+ with open(filename, 'wb') as f:
311
+ f.write(pack(obj))
312
+
313
+
314
+ def load(filename):
315
+ """从文件加载对象"""
316
+ with open(filename, 'rb') as f:
317
+ data = f.read()
318
+ return unpack(data)[0]