python - 有和没有“as”子句的上下文管理器的区别
问题描述
首先,我需要道歉,因为我还不能为我的问题提供明确的MCVE。我的问题是关于我在代码库深处遇到的一个奇怪现象,我想了解这是如何发生的,所以在某种程度上我问我如何首先为这种现象创建MCVE。
tl;博士
在根本不使用分配的变量as
的语句中是否使用子句怎么会重要?with
更长的版本
我们正在使用 Airflow(Apache 项目),其中有一个名为DAG
exists 的类。此类应该用作如下with
子句的上下文管理器:
with DAG(**some_parameters) as dag:
do_something_with(dag)
这按预期工作。
但是,在某些情况下,我们不使用子句dag
中的变量with
,因此 IDE 会发出警告,然后将其重命名为_dag
(以声明不使用),我尝试as dag
完全删除该子句:
with DAG(**some_parameters):
do_something_without_passing_dag()
根据我对 Python 的理解,这应该等同as dag
于运行时带有子句的版本:
with DAG(**some_parameters) as dag:
do_something_without_passing_dag()
但是,令人惊讶的是,在 Airflow 项目的背景下,两者之间似乎存在差异。使用该as dag
子句,代码按预期工作;如果没有该as dag
子句,则会显示错误(请参阅本文末尾)。令人沮丧的是,这个错误出现在 Airflow 进程的日志中,并且根本不包含对我的代码的引用。
我需要指出的是,在 Airflow 上下文中,这些with
语句位于小模块的顶层,因此该as
语句会创建一个模块全局变量(如果存在)。我不知道这是否相关。如果是这样,我不明白为什么。
据我了解,如果我根本不使用该变量,我是否提供子句应该不会有任何区别。as
在这里,情况似乎仍然如此。
我已经调查了三个方面:
- 我监控了类的
__enter__()
方法的输入和输出DAG
。在这两种情况下,输入(参数)和输出(返回值)都是相同的(返回值当然是上下文管理器对象)。as
因此,基于该子句的存在,这里似乎没有任何区别。 - 使用该
as
子句时,with
我在该子句中删除了变量 (del dag
) 作为第一条语句。然后这个版本的行为就像没有as
子句的版本一样,即它引发了一个错误。 - 我查看了 DAG 的源代码,发现在它的
__enter__()
方法中,它将当前上下文对象存储在一个DagContext
类中,并且do_something_without_passing_dag()
可以(并且将)DAG
从DagContext
. 但是由于这一切都独立于使用语句创建的变量as
,我不明白这有什么关系。
任何人都可以解释为什么会这样吗?
这是我可以在 Airflow 日志中找到的错误堆栈跟踪:
webserver_1 | Traceback (most recent call last):
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
webserver_1 | response = self.full_dispatch_request()
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
webserver_1 | rv = self.handle_user_exception(e)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
webserver_1 | reraise(exc_type, exc_value, tb)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
webserver_1 | raise value
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
webserver_1 | rv = self.dispatch_request()
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
webserver_1 | return self.view_functions[rule.endpoint](**req.view_args)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask_admin/base.py", line 69, in inner
webserver_1 | return self._run_view(f, *args, **kwargs)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask_admin/base.py", line 368, in _run_view
webserver_1 | return fn(self, *args, **kwargs)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/flask_login/utils.py", line 258, in decorated_view
webserver_1 | return func(*args, **kwargs)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/airflow/www/utils.py", line 281, in wrapper
webserver_1 | return f(*args, **kwargs)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/airflow/utils/db.py", line 74, in wrapper
webserver_1 | return func(*args, **kwargs)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/airflow/www/views.py", line 1958, in paused
webserver_1 | models.DagModel.get_dagmodel(dag_id).set_is_paused(is_paused=is_paused)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/airflow/utils/db.py", line 74, in wrapper
webserver_1 | return func(*args, **kwargs)
webserver_1 | File "/usr/local/lib/python3.7/site-packages/airflow/models/dag.py", line 1562, in set_is_paused
webserver_1 | subdags = self.get_dag().subdags
webserver_1 | AttributeError: 'NoneType' object has no attribute 'subdags'
解决方案
您的 do_something_without_passing_dag() 不应该知道 DAG(**some_parameters) 应该在其参数“dag”中传递。
例如,这有效:
dag=DAG(**some_parameters)
with dag:
do_something_without_passing_dag()
推荐阅读
- android - 资源样式/Theme.Base 未找到
- r - R ::tmap 在图例中绘制并显示 NA 值
- android - 服务 serveo.net 是否安全且私密?
- database - 在没有数据库的情况下运行 ddev
- vb.net - 为什么使用 Linq 从远程文件夹中的 GetFiles 挂起
- php - 通过定制器将其他页面部分添加到首页
- session - 如何在 golang 中保存会话
- python - 是否有将变量“自动完成”到所需库的功能?
- r - 在给定过滤条件的情况下按 R 中的列更新第一行的列值
- django - 有没有办法将 Django 与 Next.js 集成?