代码之家  ›  专栏  ›  技术社区  ›  Ian Newson

在“with”语句中调用构造函数

  •  5
  • Ian Newson  · 技术社区  · 4 年前

    class Test:
    
        def __init__(self, name):
            self.name = name
    
        def __enter__(self):
            print(f'entering {self.name}')
    
        def __exit__(self,
            exctype,
            excinst,
            exctb) -> bool:
            print(f'exiting {self.name}')
            return True
    
    with Test('first') as test:
        print(f'in {test.name}')
    
    test = Test('second')
    with test:
        print(f'in {test.name}')
    

    运行会产生以下输出:

    entering first
    exiting first
    entering second
    in second
    exiting second
    

    但我希望它能产生:

    entering first
    in first
    exiting first
    entering second
    in second
    exiting second
    

    为什么我的第一个示例中的代码没有被调用?

    3 回复  |  直到 4 年前
        1
  •  6
  •   Silvio Mayolo    4 年前

    这个 __enter__ 方法应返回上下文对象。 with ... as ... 使用的返回值 __进入__ 决定给你什么东西。自从你 __进入__ 不返回任何内容,而是隐式返回 None 所以 test .

    with Test('first') as test:
        print(f'in {test.name}')
    
    test = Test('second')
    with test:
        print(f'in {test.name}')
    

    所以 测试 没有。然后 test.name Test('first').__exit__ __exit__ 返回 True ,这表示错误已被处理(基本上,您的 __出口__ 他表现得像个 except 块),因此代码在第一个 with 布洛克,既然你告诉Python一切都很好。

    考虑

    def __enter__(self):
        print(f'entering {self.name}')
        return self
    

    你也可以考虑不回来 从…起 __出口__ 除非你真的打算无条件地压制 全部的 块中的错误(并充分理解抑制其他程序员错误的后果,以及 KeyboardInterrupt , StopIteration ,以及各种系统信号)

        2
  •  2
  •   NGilbert    4 年前

    我相信这种行为是因为 __enter__ 必须返回将要操作的内容,在这种情况下,将使用名称访问该内容 test . 通过改变 以下

    def __enter__(self):
        print(f"entering {self.name}")
        return self
    

    我们得到了预期的行为。

        3
  •  1
  •   juanpa.arrivillaga    4 年前

    问题是你的 __enter__ 方法返回 None test 分配 没有一个

    然后尝试访问 None.name __exit__ 方法返回 True 它将始终抑制任何错误:

    从该方法返回真值将导致with语句