tretool 0.2.1__py3-none-any.whl → 1.0.0__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.
- tretool/__init__.py +39 -12
- tretool/config.py +406 -170
- tretool/decoratorlib.py +423 -0
- tretool/encoding.py +404 -75
- tretool/httplib.py +730 -0
- tretool/jsonlib.py +619 -151
- tretool/logger.py +712 -0
- tretool/mathlib.py +0 -33
- tretool/path.py +19 -0
- tretool/platformlib.py +469 -314
- tretool/plugin.py +437 -237
- tretool/smartCache.py +569 -0
- tretool/tasklib.py +730 -0
- tretool/transform/docx.py +544 -0
- tretool/transform/pdf.py +273 -95
- tretool/ziplib.py +664 -0
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/METADATA +11 -5
- tretool-1.0.0.dist-info/RECORD +24 -0
- tretool/markfunc.py +0 -152
- tretool/memorizeTools.py +0 -24
- tretool/writeLog.py +0 -69
- tretool-0.2.1.dist-info/RECORD +0 -20
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/WHEEL +0 -0
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/top_level.txt +0 -0
tretool/smartCache.py
ADDED
@@ -0,0 +1,569 @@
|
|
1
|
+
import time
|
2
|
+
from collections import OrderedDict, defaultdict
|
3
|
+
from typing import Any, Callable, Optional, Union, Dict, List, Tuple
|
4
|
+
from functools import wraps, update_wrapper
|
5
|
+
import pickle
|
6
|
+
import hashlib
|
7
|
+
import threading
|
8
|
+
import json
|
9
|
+
import inspect
|
10
|
+
import zlib
|
11
|
+
from datetime import timedelta
|
12
|
+
import logging
|
13
|
+
|
14
|
+
# 设置日志
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
class CachePolicy:
|
18
|
+
"""缓存策略基类"""
|
19
|
+
def __init__(self, maxsize: int = 128):
|
20
|
+
self.maxsize = maxsize
|
21
|
+
|
22
|
+
def on_get(self, key: Any) -> None:
|
23
|
+
"""当获取缓存项时调用"""
|
24
|
+
pass
|
25
|
+
|
26
|
+
def on_set(self, key: Any) -> None:
|
27
|
+
"""当设置缓存项时调用"""
|
28
|
+
pass
|
29
|
+
|
30
|
+
def on_delete(self, key: Any) -> None:
|
31
|
+
"""当删除缓存项时调用"""
|
32
|
+
pass
|
33
|
+
|
34
|
+
def on_miss(self, key: Any) -> None:
|
35
|
+
"""当缓存未命中时调用"""
|
36
|
+
pass
|
37
|
+
|
38
|
+
def on_evict(self, key: Any) -> None:
|
39
|
+
"""当淘汰缓存项时调用"""
|
40
|
+
pass
|
41
|
+
|
42
|
+
def evict(self) -> Any:
|
43
|
+
"""根据策略淘汰一个缓存项,返回被淘汰的键"""
|
44
|
+
raise NotImplementedError
|
45
|
+
|
46
|
+
def clear(self) -> None:
|
47
|
+
"""清除策略状态"""
|
48
|
+
pass
|
49
|
+
|
50
|
+
class LRUPolicy(CachePolicy):
|
51
|
+
"""最近最少使用策略"""
|
52
|
+
def __init__(self, maxsize: int = 128):
|
53
|
+
super().__init__(maxsize)
|
54
|
+
self._order = OrderedDict()
|
55
|
+
|
56
|
+
def on_get(self, key: Any) -> None:
|
57
|
+
if key in self._order:
|
58
|
+
self._order.move_to_end(key)
|
59
|
+
|
60
|
+
def on_set(self, key: Any) -> None:
|
61
|
+
self._order[key] = True
|
62
|
+
self._order.move_to_end(key)
|
63
|
+
if len(self._order) > self.maxsize:
|
64
|
+
self.evict()
|
65
|
+
|
66
|
+
def on_delete(self, key: Any) -> None:
|
67
|
+
self._order.pop(key, None)
|
68
|
+
|
69
|
+
def on_evict(self, key: Any) -> None:
|
70
|
+
self._order.pop(key, None)
|
71
|
+
|
72
|
+
def evict(self) -> Any:
|
73
|
+
if not self._order:
|
74
|
+
raise ValueError("Cache is empty")
|
75
|
+
key, _ = self._order.popitem(last=False)
|
76
|
+
return key
|
77
|
+
|
78
|
+
def clear(self) -> None:
|
79
|
+
self._order.clear()
|
80
|
+
|
81
|
+
class LFUPolicy(CachePolicy):
|
82
|
+
"""最不经常使用策略"""
|
83
|
+
def __init__(self, maxsize: int = 128):
|
84
|
+
super().__init__(maxsize)
|
85
|
+
self._counts = defaultdict(int)
|
86
|
+
self._min_heap = []
|
87
|
+
|
88
|
+
def on_get(self, key: Any) -> None:
|
89
|
+
self._counts[key] += 1
|
90
|
+
|
91
|
+
def on_set(self, key: Any) -> None:
|
92
|
+
self._counts[key] = 1
|
93
|
+
if len(self._counts) > self.maxsize:
|
94
|
+
self.evict()
|
95
|
+
|
96
|
+
def on_delete(self, key: Any) -> None:
|
97
|
+
self._counts.pop(key, None)
|
98
|
+
|
99
|
+
def on_evict(self, key: Any) -> None:
|
100
|
+
self._counts.pop(key, None)
|
101
|
+
|
102
|
+
def evict(self) -> Any:
|
103
|
+
if not self._counts:
|
104
|
+
raise ValueError("Cache is empty")
|
105
|
+
|
106
|
+
# 找到使用次数最少的键
|
107
|
+
min_key = min(self._counts.keys(), key=lambda k: self._counts[k])
|
108
|
+
del self._counts[min_key]
|
109
|
+
return min_key
|
110
|
+
|
111
|
+
def clear(self) -> None:
|
112
|
+
self._counts.clear()
|
113
|
+
|
114
|
+
class FIFOPolicy(CachePolicy):
|
115
|
+
"""先进先出策略"""
|
116
|
+
def __init__(self, maxsize: int = 128):
|
117
|
+
super().__init__(maxsize)
|
118
|
+
self._queue = []
|
119
|
+
|
120
|
+
def on_set(self, key: Any) -> None:
|
121
|
+
self._queue.append(key)
|
122
|
+
if len(self._queue) > self.maxsize:
|
123
|
+
self.evict()
|
124
|
+
|
125
|
+
def on_delete(self, key: Any) -> None:
|
126
|
+
if key in self._queue:
|
127
|
+
self._queue.remove(key)
|
128
|
+
|
129
|
+
def on_evict(self, key: Any) -> None:
|
130
|
+
if key in self._queue:
|
131
|
+
self._queue.remove(key)
|
132
|
+
|
133
|
+
def evict(self) -> Any:
|
134
|
+
if not self._queue:
|
135
|
+
raise ValueError("Cache is empty")
|
136
|
+
return self._queue.pop(0)
|
137
|
+
|
138
|
+
def clear(self) -> None:
|
139
|
+
self._queue.clear()
|
140
|
+
|
141
|
+
class CacheItem:
|
142
|
+
"""缓存项"""
|
143
|
+
__slots__ = ['value', 'expire_time', 'hits', 'last_accessed', 'size']
|
144
|
+
|
145
|
+
def __init__(self, value: Any, ttl: Optional[float] = None):
|
146
|
+
self.value = value
|
147
|
+
self.expire_time = time.time() + ttl if ttl else None
|
148
|
+
self.hits = 0
|
149
|
+
self.last_accessed = time.time()
|
150
|
+
self.size = self._calculate_size(value)
|
151
|
+
|
152
|
+
def is_expired(self) -> bool:
|
153
|
+
"""检查是否已过期"""
|
154
|
+
return self.expire_time is not None and time.time() > self.expire_time
|
155
|
+
|
156
|
+
def hit(self) -> None:
|
157
|
+
"""增加命中计数"""
|
158
|
+
self.hits += 1
|
159
|
+
self.last_accessed = time.time()
|
160
|
+
|
161
|
+
def _calculate_size(self, value: Any) -> int:
|
162
|
+
"""估算缓存项大小"""
|
163
|
+
try:
|
164
|
+
return len(pickle.dumps(value))
|
165
|
+
except:
|
166
|
+
return 1 # 无法计算大小时返回1
|
167
|
+
|
168
|
+
class SmartCache:
|
169
|
+
"""智能缓存"""
|
170
|
+
def __init__(
|
171
|
+
self,
|
172
|
+
policy: Union[str, CachePolicy] = 'lru',
|
173
|
+
maxsize: int = 128,
|
174
|
+
maxmem: Optional[int] = None,
|
175
|
+
ttl: Optional[float] = None,
|
176
|
+
serializer: Optional[Callable[[Any], bytes]] = None,
|
177
|
+
deserializer: Optional[Callable[[bytes], Any]] = None,
|
178
|
+
namespace: str = 'default',
|
179
|
+
compression: bool = False
|
180
|
+
):
|
181
|
+
"""
|
182
|
+
初始化智能缓存
|
183
|
+
|
184
|
+
参数:
|
185
|
+
policy: 缓存策略 ('lru', 'lfu', 'fifo' 或 CachePolicy 实例)
|
186
|
+
maxsize: 最大缓存项数
|
187
|
+
maxmem: 最大内存使用量(MB),None表示不限制
|
188
|
+
ttl: 默认生存时间(秒),None表示永不过期
|
189
|
+
serializer: 自定义序列化函数
|
190
|
+
deserializer: 自定义反序列化函数
|
191
|
+
namespace: 缓存命名空间
|
192
|
+
compression: 是否启用压缩
|
193
|
+
"""
|
194
|
+
self._data: Dict[Any, CacheItem] = {}
|
195
|
+
self._lock = threading.RLock()
|
196
|
+
self.maxsize = maxsize
|
197
|
+
self.maxmem = maxmem * 1024 * 1024 if maxmem else None # 转换为字节
|
198
|
+
self.default_ttl = ttl
|
199
|
+
self.namespace = namespace
|
200
|
+
self.compression = compression
|
201
|
+
self.total_size = 0 # 当前总大小(字节)
|
202
|
+
|
203
|
+
self.stats = {
|
204
|
+
'hits': 0,
|
205
|
+
'misses': 0,
|
206
|
+
'evictions': 0,
|
207
|
+
'expired': 0,
|
208
|
+
'size': 0,
|
209
|
+
'compression_ratio': 0.0
|
210
|
+
}
|
211
|
+
|
212
|
+
# 设置序列化器
|
213
|
+
self.serializer = serializer or pickle.dumps
|
214
|
+
self.deserializer = deserializer or pickle.loads
|
215
|
+
|
216
|
+
# 设置缓存策略
|
217
|
+
if isinstance(policy, str):
|
218
|
+
policy = policy.lower()
|
219
|
+
if policy == 'lru':
|
220
|
+
self.policy = LRUPolicy(maxsize)
|
221
|
+
elif policy == 'lfu':
|
222
|
+
self.policy = LFUPolicy(maxsize)
|
223
|
+
elif policy == 'fifo':
|
224
|
+
self.policy = FIFOPolicy(maxsize)
|
225
|
+
else:
|
226
|
+
raise ValueError(f"Unknown cache policy: {policy}")
|
227
|
+
elif isinstance(policy, CachePolicy):
|
228
|
+
self.policy = policy
|
229
|
+
else:
|
230
|
+
raise TypeError("policy must be str or CachePolicy instance")
|
231
|
+
|
232
|
+
def __len__(self) -> int:
|
233
|
+
"""当前缓存项数量"""
|
234
|
+
return len(self._data)
|
235
|
+
|
236
|
+
def __contains__(self, key: Any) -> bool:
|
237
|
+
"""检查键是否在缓存中(未过期)"""
|
238
|
+
try:
|
239
|
+
self._get(key, update_stats=False)
|
240
|
+
return True
|
241
|
+
except KeyError:
|
242
|
+
return False
|
243
|
+
|
244
|
+
def clear(self) -> None:
|
245
|
+
"""清空缓存"""
|
246
|
+
with self._lock:
|
247
|
+
self._data.clear()
|
248
|
+
self.policy.clear()
|
249
|
+
self.total_size = 0
|
250
|
+
self.stats = {
|
251
|
+
'hits': 0,
|
252
|
+
'misses': 0,
|
253
|
+
'evictions': 0,
|
254
|
+
'expired': 0,
|
255
|
+
'size': 0,
|
256
|
+
'compression_ratio': 0.0
|
257
|
+
}
|
258
|
+
|
259
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
260
|
+
"""
|
261
|
+
获取缓存值
|
262
|
+
|
263
|
+
参数:
|
264
|
+
key: 缓存键
|
265
|
+
default: 未找到时返回的默认值
|
266
|
+
|
267
|
+
返回:
|
268
|
+
缓存值或默认值
|
269
|
+
"""
|
270
|
+
try:
|
271
|
+
return self._get(key)
|
272
|
+
except KeyError:
|
273
|
+
return default
|
274
|
+
|
275
|
+
def _get(self, key: Any, update_stats: bool = True) -> Any:
|
276
|
+
"""内部获取方法,不处理默认值"""
|
277
|
+
with self._lock:
|
278
|
+
if key not in self._data:
|
279
|
+
if update_stats:
|
280
|
+
self.stats['misses'] += 1
|
281
|
+
self.policy.on_miss(key)
|
282
|
+
raise KeyError(key)
|
283
|
+
|
284
|
+
item = self._data[key]
|
285
|
+
if item.is_expired():
|
286
|
+
del self._data[key]
|
287
|
+
self.total_size -= item.size
|
288
|
+
if update_stats:
|
289
|
+
self.stats['expired'] += 1
|
290
|
+
self.policy.on_miss(key)
|
291
|
+
raise KeyError(f"Key {key} expired")
|
292
|
+
|
293
|
+
item.hit()
|
294
|
+
if update_stats:
|
295
|
+
self.stats['hits'] += 1
|
296
|
+
self.policy.on_get(key)
|
297
|
+
return item.value
|
298
|
+
|
299
|
+
def set(self, key: Any, value: Any, ttl: Optional[float] = None) -> None:
|
300
|
+
"""
|
301
|
+
设置缓存值
|
302
|
+
|
303
|
+
参数:
|
304
|
+
key: 缓存键
|
305
|
+
value: 缓存值
|
306
|
+
ttl: 生存时间(秒),None表示使用默认ttl
|
307
|
+
"""
|
308
|
+
with self._lock:
|
309
|
+
# 如果键已存在,先删除
|
310
|
+
if key in self._data:
|
311
|
+
self._delete(key, update_stats=False)
|
312
|
+
|
313
|
+
# 检查是否需要淘汰
|
314
|
+
while len(self._data) >= self.maxsize or (
|
315
|
+
self.maxmem is not None and self.total_size >= self.maxmem
|
316
|
+
):
|
317
|
+
self._evict()
|
318
|
+
|
319
|
+
# 压缩数据
|
320
|
+
if self.compression:
|
321
|
+
try:
|
322
|
+
value = self._compress(value)
|
323
|
+
except Exception as e:
|
324
|
+
logger.warning(f"Compression failed: {str(e)}")
|
325
|
+
|
326
|
+
ttl = ttl if ttl is not None else self.default_ttl
|
327
|
+
item = CacheItem(value, ttl)
|
328
|
+
self._data[key] = item
|
329
|
+
self.total_size += item.size
|
330
|
+
self.policy.on_set(key)
|
331
|
+
self.stats['size'] = self.total_size
|
332
|
+
|
333
|
+
def _compress(self, data: Any) -> Any:
|
334
|
+
"""压缩数据"""
|
335
|
+
serialized = self.serializer(data)
|
336
|
+
compressed = zlib.compress(serialized)
|
337
|
+
self.stats['compression_ratio'] = len(compressed) / len(serialized)
|
338
|
+
return compressed
|
339
|
+
|
340
|
+
def _decompress(self, data: Any) -> Any:
|
341
|
+
"""解压数据"""
|
342
|
+
if not self.compression:
|
343
|
+
return data
|
344
|
+
return self.deserializer(zlib.decompress(data))
|
345
|
+
|
346
|
+
def delete(self, key: Any) -> bool:
|
347
|
+
"""
|
348
|
+
删除缓存项
|
349
|
+
|
350
|
+
返回:
|
351
|
+
是否成功删除
|
352
|
+
"""
|
353
|
+
with self._lock:
|
354
|
+
return self._delete(key)
|
355
|
+
|
356
|
+
def _delete(self, key: Any, update_stats: bool = True) -> bool:
|
357
|
+
"""内部删除方法"""
|
358
|
+
if key in self._data:
|
359
|
+
item = self._data[key]
|
360
|
+
del self._data[key]
|
361
|
+
self.total_size -= item.size
|
362
|
+
if update_stats:
|
363
|
+
self.policy.on_delete(key)
|
364
|
+
return True
|
365
|
+
return False
|
366
|
+
|
367
|
+
def _evict(self) -> None:
|
368
|
+
"""根据策略淘汰一个缓存项"""
|
369
|
+
with self._lock:
|
370
|
+
try:
|
371
|
+
key = self.policy.evict()
|
372
|
+
if key in self._data:
|
373
|
+
item = self._data[key]
|
374
|
+
del self._data[key]
|
375
|
+
self.total_size -= item.size
|
376
|
+
self.stats['evictions'] += 1
|
377
|
+
self.policy.on_evict(key)
|
378
|
+
except ValueError:
|
379
|
+
pass # 缓存为空
|
380
|
+
|
381
|
+
def keys(self) -> List[Any]:
|
382
|
+
"""获取所有未过期的键"""
|
383
|
+
with self._lock:
|
384
|
+
return [k for k in self._data if not self._data[k].is_expired()]
|
385
|
+
|
386
|
+
def values(self) -> List[Any]:
|
387
|
+
"""获取所有未过期的值"""
|
388
|
+
with self._lock:
|
389
|
+
return [self._get(k) for k in self.keys()]
|
390
|
+
|
391
|
+
def items(self) -> List[Tuple[Any, Any]]:
|
392
|
+
"""获取所有未过期的键值对"""
|
393
|
+
with self._lock:
|
394
|
+
return [(k, self._get(k)) for k in self.keys()]
|
395
|
+
|
396
|
+
def get_stats(self) -> Dict[str, Any]:
|
397
|
+
"""获取缓存统计信息"""
|
398
|
+
with self._lock:
|
399
|
+
stats = self.stats.copy()
|
400
|
+
stats.update({
|
401
|
+
'current_size': len(self._data),
|
402
|
+
'max_size': self.maxsize,
|
403
|
+
'memory_usage': f"{self.total_size / (1024 * 1024):.2f}MB",
|
404
|
+
'max_memory': f"{self.maxmem / (1024 * 1024):.2f}MB" if self.maxmem else "unlimited",
|
405
|
+
'namespace': self.namespace,
|
406
|
+
'policy': self.policy.__class__.__name__,
|
407
|
+
'compression': self.compression,
|
408
|
+
'avg_hit_rate': stats['hits'] / max(1, stats['hits'] + stats['misses'])
|
409
|
+
})
|
410
|
+
return stats
|
411
|
+
|
412
|
+
def persist(self, filepath: str) -> None:
|
413
|
+
"""持久化缓存到文件"""
|
414
|
+
with self._lock:
|
415
|
+
data = {
|
416
|
+
'items': {k: (self.serializer(v.value), v.expire_time)
|
417
|
+
for k, v in self._data.items()
|
418
|
+
if not v.is_expired()},
|
419
|
+
'stats': self.stats,
|
420
|
+
'namespace': self.namespace,
|
421
|
+
'compression': self.compression
|
422
|
+
}
|
423
|
+
with open(filepath, 'wb') as f:
|
424
|
+
pickle.dump(data, f)
|
425
|
+
|
426
|
+
def load(self, filepath: str) -> None:
|
427
|
+
"""从文件加载缓存"""
|
428
|
+
with self._lock:
|
429
|
+
with open(filepath, 'rb') as f:
|
430
|
+
data = pickle.load(f)
|
431
|
+
|
432
|
+
if data.get('namespace') != self.namespace:
|
433
|
+
raise ValueError("Namespace mismatch")
|
434
|
+
|
435
|
+
self.clear()
|
436
|
+
self.compression = data.get('compression', False)
|
437
|
+
|
438
|
+
for k, v in data['items'].items():
|
439
|
+
value = self.deserializer(v[0])
|
440
|
+
if self.compression:
|
441
|
+
value = self._decompress(value)
|
442
|
+
|
443
|
+
ttl = (v[1] - time.time()) if v[1] is not None else None
|
444
|
+
self._data[k] = CacheItem(value, ttl)
|
445
|
+
|
446
|
+
self.stats = data['stats']
|
447
|
+
|
448
|
+
def memoize(
|
449
|
+
self,
|
450
|
+
ttl: Optional[float] = None,
|
451
|
+
key_func: Optional[Callable] = None,
|
452
|
+
unless: Optional[Callable] = None
|
453
|
+
):
|
454
|
+
"""
|
455
|
+
装饰器,缓存函数结果
|
456
|
+
|
457
|
+
参数:
|
458
|
+
ttl: 生存时间(秒)
|
459
|
+
key_func: 自定义缓存键生成函数
|
460
|
+
unless: 条件函数,返回True时不缓存
|
461
|
+
"""
|
462
|
+
def decorator(func):
|
463
|
+
@wraps(func)
|
464
|
+
def wrapper(*args, **kwargs):
|
465
|
+
# 检查是否应该跳过缓存
|
466
|
+
if unless and unless(*args, **kwargs):
|
467
|
+
return func(*args, **kwargs)
|
468
|
+
|
469
|
+
cache_key = self._make_cache_key(func, args, kwargs, key_func)
|
470
|
+
try:
|
471
|
+
return self.get(cache_key)
|
472
|
+
except KeyError:
|
473
|
+
result = func(*args, **kwargs)
|
474
|
+
self.set(cache_key, result, ttl)
|
475
|
+
return result
|
476
|
+
|
477
|
+
def invalidate(*args, **kwargs):
|
478
|
+
"""使缓存项失效"""
|
479
|
+
cache_key = self._make_cache_key(func, args, kwargs, key_func)
|
480
|
+
self.delete(cache_key)
|
481
|
+
|
482
|
+
wrapper.invalidate = invalidate
|
483
|
+
return wrapper
|
484
|
+
return decorator
|
485
|
+
|
486
|
+
def _make_cache_key(
|
487
|
+
self,
|
488
|
+
func: Callable,
|
489
|
+
args: tuple,
|
490
|
+
kwargs: dict,
|
491
|
+
key_func: Optional[Callable] = None
|
492
|
+
) -> str:
|
493
|
+
"""生成缓存键"""
|
494
|
+
if key_func:
|
495
|
+
return key_func(func, args, kwargs)
|
496
|
+
|
497
|
+
# 获取函数签名
|
498
|
+
sig = inspect.signature(func)
|
499
|
+
bound_args = sig.bind(*args, **kwargs)
|
500
|
+
bound_args.apply_defaults()
|
501
|
+
|
502
|
+
# 生成键
|
503
|
+
key_parts = [
|
504
|
+
func.__module__,
|
505
|
+
func.__qualname__,
|
506
|
+
str(bound_args.arguments)
|
507
|
+
]
|
508
|
+
key = "|".join(key_parts)
|
509
|
+
return hashlib.sha256(key.encode('utf-8')).hexdigest()
|
510
|
+
|
511
|
+
def ttl(self, key: Any) -> Optional[float]:
|
512
|
+
"""
|
513
|
+
获取剩余生存时间(秒)
|
514
|
+
|
515
|
+
返回:
|
516
|
+
剩余时间(秒),None表示永不过期,-1表示键不存在或已过期
|
517
|
+
"""
|
518
|
+
with self._lock:
|
519
|
+
if key not in self._data:
|
520
|
+
return -1
|
521
|
+
|
522
|
+
item = self._data[key]
|
523
|
+
if item.is_expired():
|
524
|
+
return -1
|
525
|
+
|
526
|
+
if item.expire_time is None:
|
527
|
+
return None
|
528
|
+
|
529
|
+
return max(0, item.expire_time - time.time())
|
530
|
+
|
531
|
+
def expire(self, key: Any, ttl: float) -> bool:
|
532
|
+
"""
|
533
|
+
设置键的生存时间
|
534
|
+
|
535
|
+
参数:
|
536
|
+
key: 缓存键
|
537
|
+
ttl: 生存时间(秒)
|
538
|
+
|
539
|
+
返回:
|
540
|
+
是否设置成功
|
541
|
+
"""
|
542
|
+
with self._lock:
|
543
|
+
if key not in self._data or self._data[key].is_expired():
|
544
|
+
return False
|
545
|
+
|
546
|
+
self._data[key].expire_time = time.time() + ttl
|
547
|
+
return True
|
548
|
+
|
549
|
+
def touch(self, key: Any) -> bool:
|
550
|
+
"""
|
551
|
+
更新键的最后访问时间
|
552
|
+
|
553
|
+
返回:
|
554
|
+
是否更新成功
|
555
|
+
"""
|
556
|
+
with self._lock:
|
557
|
+
if key not in self._data or self._data[key].is_expired():
|
558
|
+
return False
|
559
|
+
|
560
|
+
self._data[key].last_accessed = time.time()
|
561
|
+
self.policy.on_get(key)
|
562
|
+
return True
|
563
|
+
|
564
|
+
def create_cache(namespace: str = 'default', **kwargs) -> SmartCache:
|
565
|
+
"""创建缓存实例的工厂函数"""
|
566
|
+
return SmartCache(namespace=namespace, **kwargs)
|
567
|
+
|
568
|
+
# 全局默认缓存
|
569
|
+
default_cache = SmartCache()
|