首先,我是 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.. 感谢您的帮助。

#1楼 票数:1 已采纳

这不是您假设使用上下文管理器的方式。 首先 OO 原则建议进行适当的封装,这意味着用户不必知道实现细节。

我会提出以下设计:

  • 上下文管理器将列表作为其创建参数
  • 它提供了两种方法:
    • append(val)准备将 val 附加到列表并返回自身以允许链接
    • append appending()返回要追加的项目列表
  • 仅当未引发异常时才附加准备好的项目

可能的实现:

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]

#2楼 票数:0

你的代码被追加两次。 你的第一个追加是在你的 Contextmanager 的语句块中(这一行: print("Changed list: {}".format(t.current()))

您的第二个 append 位于__exit__方法中,该方法在 Contextmanager 完成其语句块后调用。

您的代码工作如下:

创建一个并填充 1,2,3
上下文管理器开始工作:
-> 深拷贝 a 到 b
-> 首先通过t.current()追加
-> __exit__结束 -> 在第二个追加的位置调用__exit__

希望它可以帮助您更好地理解它。

  ask by Slayer598 translate from so

未解决问题?本站智能推荐:

1回复

使用上下文管理器选择数据库或文件处理程序

我希望能够使用上下文管理器根据参数打开FileHandler或DBHandler 。 这两个类本身就是上下文管理器。 我可以想出下面的代码,想知道是否有更好的方法来做到这一点(请忽略任何缺失的函数)?
1回复

“AttributeError: 'NoneType' 对象没有属性 'test'” 使用上下文管理器

我有这门课: class Tess: def __init__(self, **kwargs): self.kwargs = kwargs def __enter__(self): print('fire away!') for ke
2回复

在 `with` 语句中启动多个上下文管理器时使用 `and` 而不是 `,`

在编写单元测试时,我经常使用以下模式: with self.subTest("Invalid input") and self.assertRaises(ValueError): ... 但只有今天笔者了解到, 根据蟒蛇的规格,我应该使用,在这里: 并且规格没有提及and作为选项。 然而
1回复

在上下文管理器中捕获异常

试图了解如何捕获/处理上下文管理器的异常: import contextlib import urllib with contxtlib.closing( urllib.request.urlopen(some_url) ) as resp: return resp.read()
3回复

为什么模块不能是上下文管理器(对于“with”语句)?

假设我们有以下mod.py : 以及它的以下用途: 我收到一个错误: Traceback (most recent call last): File "./test.py", line 3, in <module> with mod: AttributeError:
3回复

根据条件使用不同的上下文管理器

是否可以根据某些条件使用不同的上下文管理器执行单个块? 例: 一种方法是将...包装成一个函数,但在我的情况下这可能不太方便。 还有其他可能吗?
2回复

使用带有 mysql 连接器 python 的上下文管理器

我正在将我的代码从 sqlite 数据库移动到 mysql,但上下文管理器出现问题,出现以下属性错误。 我试过将 mydb.cursor() 组合为游标,mydb: 等...
1回复

获取使用@contextmanager创建的上下文管理器可以正常使用异常

我有以下代码 现在它打印出来了 这告诉我上下文管理器没有关闭。 如何让它关闭并打印“完成的上下文管理器”行? 因为我正在使用装饰器,所以我没有专门的__exit__函数,我认为应该根据它调用它 。 因此,我不确定如何在其上下文中发生错误的情况下让我的上下文管理器退出