我有以下代码:

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

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

推荐答案

__enter__方法应该返回上下文对象.with ... as ...使用返回值__enter__来确定要给您的对象.因为你的__enter__不返回任何东西,它隐式地返回None,所以test就是None.

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

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

所以test是零.那么test.name是一个错误.该错误被引发,因此Test('first').__exit__被调用.__exit__返回True,这表示错误已被处理(本质上,__exit__的行为类似于except块),因此代码在第一个with块之后继续,因为您告诉Python一切正常.

考虑

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

您也可以考虑不要从__exit__返回True,除非您真正打算无条件地 suppress 块中的all个错误(并且完全理解 suppress 其他程序员错误的后果,以及KeyboardInterrupt, StopIteration,以及各种系统信号).

Python-3.x相关问答推荐

Django 5.0.2和django_rest_framework

使用Python装载. iso文件

将Trio与基于线程的事件侦听器混合使用

CONNEXION.EXCEPTIONS.ResolverError:运行pyz文件时未命名模块

将f-字符串放置在f-字符串内

我不能使用拆分来分隔数据

Heroku 中的未知错误代码缺少一个或多个参数

添加任意数量的 pandas 数据框

将值从函数传递到标签

将水平堆叠的数据排列成垂直

如何统计一个值连续出现的次数?

Keras 中 Conv2D 层的意外结果

为什么 return node.next 会返回整个链表?

是否将dict转换为一个数据帧,每个值都有重复的键?

在初始化之前禁用`__setattr__`的干净方法

PySpark python 问题:Py4JJavaError: An error occurred while calling o48.showString

PIL 在图像上绘制半透明方形覆盖

Python3 - 如何从现有抽象类定义抽象子类?

Django Rest 框架 ListField 和 DictField

如何从Pandas 中的字符串中提取前8个字符