Python未带as子句的with语句作用及DearPyGui报错问题
DearPyGui 容器控件with语句作用问题
问题复现
以下代码在完成依赖导入、运行环境初始化的前提下可正常运行:
with dpg.window(label="Window"): dpg.add_text("Hello, world") dpg.add_button(label="Save") dpg.add_input_text(label="string", default_value="Quick brown fox") dpg.add_slider_float(label="float", default_value=0.273, max_value=1) dpg.add_color_picker(label="Pick", default_value=(0, 0, 0))
去掉with语句直接按顺序调用API的代码无法正常运行,执行到第2行就会抛出运行时错误:
dpg.window(label="Window") dpg.add_text("Hello, world") dpg.add_button(label="Save") dpg.add_input_text(label="string", default_value="Quick brown fox") dpg.add_slider_float(label="float", default_value=0.273, max_value=1) dpg.add_color_picker(label="Pick", default_value=(0, 0, 0))
对应的报错堆栈如下:
The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\18328\PycharmProjects\sandbox\main.py", line 10, in <module> dpg.add_text("Hello, world") File "C:\Users\18328\AppData\Local\Programs\Python\Python39\lib\site-packages\dearpygui\dearpygui.py", line 7019, in add_text return internal_dpg.add_text(default_value, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, source=source, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, wrap=wrap, bullet=bullet, color=color, show_label=show_label, **kwargs) SystemError: <built-in function add_text> returned a result with an error set
核心疑问:未使用as子句绑定返回对象的with语句,为什么会影响代码块内部的执行逻辑?
原因解答
这个现象和with语句是否用as绑定返回值没有任何关系,核心是DearPyGui的控件层级挂载机制完全依托上下文管理器实现:
dpg.window这类容器控件都实现了Python上下文管理器协议,自带__enter__和__exit__方法。用with调用容器控件时,进入代码块的瞬间,当前容器会被压入DearPyGui内部维护的父容器栈栈顶;代码块内所有add_xxx创建控件的方法,默认都会把栈顶容器作为新控件的父节点,自动完成层级挂载。with代码块执行结束后,__exit__方法会自动把该容器从栈顶弹出,恢复之前的栈状态。- 脱离
with语句单独调用dpg.window(label="Window")时,这行代码虽然会创建窗口对象,但不会触发容器入栈逻辑,后续执行dpg.add_text()时,内部找不到合法的父容器挂载新控件,就会直接抛出运行时错误。哪怕你用变量接收dpg.window()的返回值,只要不用with包裹后续的控件创建代码,报错依然会出现。
如果不想使用with语法,也可以手动给每个add_xxx方法传入parent参数,明确指定新控件挂载的父控件标签,不过官方推荐始终使用with写法管理容器层级,能避免大量手动传参导致的挂载错误。
内容的提问来源于stack exchange,提问作者Bowen Yang
相关产品推荐
相关产品推荐

