提问人:Денис Торопов 提问时间:9/22/2023 更新时间:9/22/2023 访问量:51
Python -类内容管理器.如果你把产量放在里面__exit__为什么会省略这个方法?
Python - Class Content manager. Why __exit__ method is omitted if you put yield inside of it?
问:
class OracleConnected():
def __init__(self):
self.oracle_username = oracle_username[1]
self.oracle_password = oracle_password[1]
self.dsn = cx_Oracle.makedsn(hostname[1], port[1], sid[1])
def __enter__(self):
try:
print('Then this')
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
self.connection = cx_Oracle.connect(user=self.oracle_username, password=self.oracle_password, dsn=self.dsn)
except Exception as e:
print(f'Error connecting to Oracle: \n{e}')
else:
yield self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
print('Finally do this')
#self.connection.close()
yield self.connection.close()
with OracleConnected() as connection:
print('It first do this')
cur = next(connection).cursor()
cur.execute("select *From payments where id = 324986093")
print(cur.fetchall())
如果一切都保持不变,我得到: 它首先执行此操作 然后这个 [(324986093, 391908893, 391908893, 1228, 无, datetime.datetime(2023, 4, 24, 0, 0)]
而不是 yield self.connection.close() -> 只写 self.connection.close(): 它首先执行此操作 然后这个 [(324986093, 391908893, 391908893, 1228, 无, datetime.datetime(2023, 4, 24, 0, 0)] 最后,执行此操作
那么问题来了,产量有什么特别之处,它给我带来了这么多麻烦?
P.S. 另外,返回 self.connection.close() -> 而不是 yield self.connection.close() 我得到了想要的答案: 它首先执行此操作 然后这个 [(324986093, 391908893, 391908893, 1228, 无, datetime.datetime(2023, 4, 24, 0, 0)] 最后,执行此操作
附言最重要的是,如果我可以问 - 想象一下我们解决了这个谜团。同一代码中的另一个问题,如果我在使用 self.connection 连接到服务器时遇到错误并说它给出错误,那么我将此错误传递给退出,退出也给了我一个错误 - 如何处理这种情况。所以我没有通过它退出?
我试着阅读文档,但似乎没有任何效果。我只是好奇省略退出的原因是什么
答:
__enter__
并且不应该有,因为那样它们将返回一个生成器,并且您必须遍历生成器才能完成该方法的执行。__exit__
yield
您可能会与 @contextlib.contextmanager
混淆,后者是一个装饰器,可以应用于生成器函数以创建简单的上下文管理器,而无需编写带有 和 的类。__enter__
__exit__
评论
yield
with
next(connection)
OracleConnected()
yield
return
__exit__
__enter__
connection
with OracleConnected() as connection:
next(connection)
self.connection
yield self.connection
__exit__
next()
next()
__enter__
print('Then this')
评论
yield
return
yield
yield
return
yield
yield
不会完全跳过该方法。它只是表现不同。调用时,不是立即执行函数体,而是返回一个生成器。如果稍后调用返回的生成器(直接调用或通过迭代它),则将执行函数体,直到它执行语句。阅读有关产量
和发电机的信息。这比随机尝试它们,然后试图从某人那里获得多余的、个性化的解释要有意义得多。__exit__
next
yield
yield
next
yield