python - 在上下文管理器中处理文件系统撤消操作的简洁有效的方法
问题描述
我正在为个人项目开发资产管理系统。我的问题是如何干净有效地处理 python 中的文件系统操作,以便在出现问题时可以回滚或撤消更改。
一个典型的操作可能看起来像这样
try
file system operation(s)
update database
except Exceptions
undo file system operations already performed
rollback database transaction
handle exceptions
文件系统操作可以是创建、复制、链接和删除文件/目录
我的想法是为文件系统操作和数据库管理提供一个上下文管理器。执行将是这样的:
# create new asset
with FileSystemCM as fs, DatabaseCM as db:
fs.create_dir(path_to_asset)
fs.create_file(path_to_a_file_this_asset_needs)
db.insert('Asset_Table', asset_name)
现在,例如 db.insert 失败,FileSystemCM 删除新创建的文件和新创建的目录,并且 DatabaseCM 回滚 db 事务
我的 FileSystemCM 实现的一个简单方法是这样的:
class FileSystemCM(object):
""" File System Context Manager """
def __init__(self):
self.undo_stack = [] # list of (fn, args, kwargs)
def __enter__(self):
return self
def __exit__(self, exception_type, exception_val, traceback):
if exception_type:
# pop undo actions off the stack and execute
while self.undo_stack:
undo_fn, args, kwargs = self.undo_stack.pop()
undo_fn(*args, **kwargs)
def create_dir(self, dir_path):
create_file(dir_path)
self.undo_stack.append((remove_dir, [dir_path], {'force': True}))
def create_file(self, file_path):
create_file(file_path)
self.undo_stack.append((remove_file, [file_path], {'force': True}))
有更好的方法吗?在某些情况下,此实现无法处理,我可以使用反馈
删除文件。我的想法是将要删除的文件移动到临时位置(或创建一个 tmp 硬链接),如果一切正常,则删除临时文件或链接,否则将其恢复。但这可能导致以下情况。
__exit__ 代码抛出异常并且没有完成撤消操作,也许我留下了一个日志文件,所以至少可以手动清理一些东西?
解决方案
我的意思是这是评论,但它太长了,不适合评论部分。首先让我说这听起来是一个非常有趣的项目(至少在我看来)。
前一段时间(我不记得在哪里)我读过一篇关于实现撤消/重做功能的文章,他们所做的是维护两个独立的堆栈(一个用于撤消,一个用于重做)。当用户执行一个动作时,一对带有参数的动作/它的反转被推入撤消堆栈。每当用户执行撤消操作时,都会执行该对的反向操作,然后将该对移动到重做堆栈中,当执行重做操作时,执行该对的操作并将该对返回到撤消堆栈.
每当用户执行新操作时,重做堆栈就会被清除。这种方法的唯一缺点是不可逆转的动作。我能想到的一种方法是使用某种事件溯源模式来保持系统的整个状态及其差异。这可能看起来非常低效,但它通常用于软件中。
推荐阅读
- python - 具有线性约束的非凸优化
- tailwind-css - Tailwind - 为什么与 Bootstrap 不同,移动设备的无前缀类?
- swift - SwiftUI 协议作为类型:值不能符合“可识别”;只有结构/枚举/类类型可以符合协议
- scala - 如何指定元组类型签名
- html - 即使我多次调用 Canvas 也不会出现多次
- python - 合并两个训练有素的网络以按顺序进行推理
- android - Flutter 项目 AndroidManifest.xml 文件显示编译错误但应用程序在 android 上运行
- javascript - 反应:道具没有正确更新
- file - 从 IntelliJ 的“项目”窗格中显示 Finder (macOS) 中选定文件的位置
- django - Django admin GenericForeignKey object_id lookup