如何使用上下文管理器以原子方式(退出时)在列表中附加值?
How to append values in list atomically (on exit) using context manager?
首先,我是 Python 的新手。
我正在尝试编写自己的上下文管理器,它会在退出时将值附加到我的列表中。我创建了列表的副本,但这似乎无法正常工作。
这是我的代码:
import time
import copy
a = [1,2,3]
class contextmanager():
def __init__(self, var):
self.abc = var
def current(self):
b.append(98325)
return b
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('Current list: {}'.format(self.current()))
with contextmanager(a) as t:
time.sleep(1)
b = copy.deepcopy(a)
print("Changed list: {}".format(t.current()))
time.sleep(2)
我想在退出时添加值,例如:
当前 - [1,2,3]
附加 - [4,5,6]
退出前 - [1,2,3]
退出 - [1,2,3,4,5,6]
但结果并非如此,我明白了:
当前 - [1,2,3,4,5,6]
附加 - [4,5,6]
退出 - [1,2,3,4,5,6,4,5,6]
我做错了什么?我该怎么做才能修复它?如果您向我展示我需要在代码中更改的内容,我会很高兴。
我似乎还不太了解 Python..
感谢您的帮助。
这不是您使用上下文管理器的方式。 First OO 原则建议进行适当的封装,这意味着用户不必知道实现细节。
我会提出以下设计:
- 上下文管理器将列表作为其创建参数
- 它提供了2种方法:
append(val)
准备 将 val 附加到列表和 returns 本身以允许链接
appending()
returns 要附加的项目列表
- 仅当未引发异常时才附加准备好的项目
可能的实现:
class contextmanager():
def __init__(self, var):
self.orig = var
self.cur = []
def append(self, val):
self.cur.append(val)
return self
def appending(self):
return self.cur
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.orig.extend(self.cur)
用法示例:
a = [1,2,3]
print("initial", a)
with contextmanager(a) as t:
t.append(4)
print("appending", t.appending())
t.append(5).append(6)
print("appending", t.appending())
print("first pass", a)
try:
with contextmanager(a) as t:
t.append(7)
t.append(8)
print("appending", t.appending())
raise Exception()
t.append(9)
print("appending", t.appending())
except Exception as e:
print("Exception", e)
print("final", a)
给出:
initial [1, 2, 3]
appending [4]
appending [4, 5, 6]
first pass [1, 2, 3, 4, 5, 6]
appending [7, 8]
Exception
final [1, 2, 3, 4, 5, 6]
你的代码被追加了两次。
您的第一个追加是在上下文管理器的语句块中(此行:print("Changed list: {}".format(t.current()))
)
您的第二个追加是在 __exit__
方法中,该方法在 Contextmanager 完成其语句块后调用。
您的代码工作如下:
创建一个并填充 1,2,3
contextmanager 开始工作:
-> 深度复制 a 到 b
-> 首先通过 t.current()
追加
-> contextmanager 结束 -> 调用 __exit__
第二个追加所在的位置。
希望它能帮助你更好地理解它。
首先,我是 Python 的新手。
我正在尝试编写自己的上下文管理器,它会在退出时将值附加到我的列表中。我创建了列表的副本,但这似乎无法正常工作。
这是我的代码:
import time
import copy
a = [1,2,3]
class contextmanager():
def __init__(self, var):
self.abc = var
def current(self):
b.append(98325)
return b
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('Current list: {}'.format(self.current()))
with contextmanager(a) as t:
time.sleep(1)
b = copy.deepcopy(a)
print("Changed list: {}".format(t.current()))
time.sleep(2)
我想在退出时添加值,例如:
当前 - [1,2,3]
附加 - [4,5,6]
退出前 - [1,2,3]
退出 - [1,2,3,4,5,6]
但结果并非如此,我明白了:
当前 - [1,2,3,4,5,6]
附加 - [4,5,6]
退出 - [1,2,3,4,5,6,4,5,6]
我做错了什么?我该怎么做才能修复它?如果您向我展示我需要在代码中更改的内容,我会很高兴。
我似乎还不太了解 Python.. 感谢您的帮助。
这不是您使用上下文管理器的方式。 First OO 原则建议进行适当的封装,这意味着用户不必知道实现细节。
我会提出以下设计:
- 上下文管理器将列表作为其创建参数
- 它提供了2种方法:
append(val)
准备 将 val 附加到列表和 returns 本身以允许链接appending()
returns 要附加的项目列表
- 仅当未引发异常时才附加准备好的项目
可能的实现:
class contextmanager():
def __init__(self, var):
self.orig = var
self.cur = []
def append(self, val):
self.cur.append(val)
return self
def appending(self):
return self.cur
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.orig.extend(self.cur)
用法示例:
a = [1,2,3]
print("initial", a)
with contextmanager(a) as t:
t.append(4)
print("appending", t.appending())
t.append(5).append(6)
print("appending", t.appending())
print("first pass", a)
try:
with contextmanager(a) as t:
t.append(7)
t.append(8)
print("appending", t.appending())
raise Exception()
t.append(9)
print("appending", t.appending())
except Exception as e:
print("Exception", e)
print("final", a)
给出:
initial [1, 2, 3]
appending [4]
appending [4, 5, 6]
first pass [1, 2, 3, 4, 5, 6]
appending [7, 8]
Exception
final [1, 2, 3, 4, 5, 6]
你的代码被追加了两次。
您的第一个追加是在上下文管理器的语句块中(此行:print("Changed list: {}".format(t.current()))
)
您的第二个追加是在 __exit__
方法中,该方法在 Contextmanager 完成其语句块后调用。
您的代码工作如下:
创建一个并填充 1,2,3
contextmanager 开始工作:
-> 深度复制 a 到 b
-> 首先通过 t.current()
追加
-> contextmanager 结束 -> 调用 __exit__
第二个追加所在的位置。
希望它能帮助你更好地理解它。