使用Kivy ScreenManager时遭遇AttributeError错误的原因咨询
AttributeError 错误原因解析 问题背景
使用Kivy的ScreenManager时触发AttributeError: 'super' object has no attribute '__getattr__'错误,已找到修复方案,但不确定错误是否因「退出第一个屏幕后才创建第二个屏幕」导致。
出错的Python代码
from kivy.lang import Builder from kivymd.app import MDApp from kivy.uix.screenmanager import Screen, ScreenManager class Card1(Screen): pass class Card2(Screen): pass class Card3(Screen): pass class MyScreenManager(ScreenManager): pass class MyApp(MDApp): selected_cards = list() def build(self): self.title = "My Card Magic Game" self.theme_cls.theme_style = "Dark" return Builder.load_file("ui1.kv") def append(self, instance): self.selected_cards.append(instance) def show_result(self): self.root.ids.welcome_label.text = f"{sum(self.selected_cards)}" MyApp().run()
出错的kv代码
MyScreenManager: Card1: Card2: Card3: <Card1> name: "first_screen" MDCard: size_hint: None, None size: 300, 400 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 25 spacing: 25 orientation: "vertical" MDLabel: text: "Hello" halign: "center" MDRoundFlatButton: text: "Yes" pos_hint: {"center_x": 0.5} on_press: app.append(1) on_release: app.root.current = "second_screen" MDRoundFlatButton: text: "No" pos_hint: {"center_x": 0.5} on_release: app.root.current = "second_screen" <Card2> name: "second_screen" MDCard: size_hint: None, None size: 300, 400 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 25 spacing: 25 orientation: "vertical" MDLabel: text: "World" halign: "center" MDRoundFlatButton: text: "Yes" pos_hint: {"center_x": 0.5} on_press: app.append(2) on_release: app.root.current = "third_screen" app.show_result() MDRoundFlatButton: text: "No" pos_hint: {"center_x": 0.5} on_release: app.root.current = "third_screen" app.show_result() <Card3> name: "third_screen" MDCard: size_hint: None, None size: 300, 400 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 25 spacing: 25 orientation: "vertical" MDLabel: id: welcome_label text: "Three" halign: "center"
错误回溯信息
[INFO ] [Logger ] Record log in C:\Users\Admin\.kivy\logs\kivy_22-08-06_69.txt [INFO ] [deps ] Successfully imported "kivy_deps.angle" 0.3.2 [INFO ] [deps ] Successfully imported "kivy_deps.glew" 0.3.1 [INFO ] [deps ] Successfully imported "kivy_deps.sdl2" 0.4.5 [INFO ] [Kivy ] v2.1.0 [INFO ] [Kivy ] Installed at "D:\Projects\Python Project\venv\lib\site-packages\kivy\__init__.py" [INFO ] [Python ] v3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] [INFO ] [Python ] Interpreter at "D:\Projects\Python Project\venv\Scripts\python.exe" [INFO ] [Logger ] Purge log fired. Processing... [INFO ] [Logger ] Purge finished! [INFO ] [Factory ] 189 symbols loaded [INFO ] [KivyMD ] 0.104.2, git-bc7d1f5, 2021-06-06 (installed at "D:\Projects\Python Project\venv\lib\site-packages\kivymd\__init__.py") [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil (img_ffpyplayer ignored) [INFO ] [Text ] Provider: sdl2 [INFO ] [Window ] Provider: sdl2 [INFO ] [GL ] Using the "OpenGL" graphics system [INFO ] [GL ] GLEW initialization succeeded [INFO ] [GL ] Backend used <glew> [INFO ] [GL ] OpenGL version <b'4.6.0 - Build 30.0.101.1338'> [INFO ] [GL ] OpenGL vendor <b'Intel'> [INFO ] [GL ] OpenGL renderer <b'Intel(R) HD Graphics 520'> [INFO ] [GL ] OpenGL parsed version: 4, 6 [INFO ] [GL ] Shading version <b'4.60 - Build 30.0.101.1338'> [INFO ] [GL ] Texture max size <16384> [INFO ] [GL ] Texture max units <32> [INFO ] [Window ] auto add sdl2 input provider [INFO ] [Window ] virtual keyboard not allowed, single mode, not docked [INFO ] [GL ] NPOT texture support is available [INFO ] [Base ] Start application main loop [INFO ] [Base ] Leaving application in progress... Traceback (most recent call last): File "kivy\properties.pyx", line 961, in kivy.properties.ObservableDict.__getattr__ KeyError: 'welcome_label' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "D:\Projects\Python Project\Kivy Training\card.py", line 59, in <module> MyApp().run() File "D:\Projects\Python Project\venv\lib\site-packages\kivy\app.py", line 955, in run runTouchApp() File "D:\Projects\Python Project\venv\lib\site-packages\kivy\base.py", line 574, in runTouchApp EventLoop.mainloop() File "D:\Projects\Python Project\venv\lib\site-packages\kivy\base.py", line 339, in mainloop self.idle() File "D:\Projects\Python Project\venv\lib\site-packages\kivy\base.py", line 383, in idle self.dispatch_input() File "D:\Projects\Python Project\venv\lib\site-packages\kivy\base.py", line 334, in dispatch_input post_dispatch_input(*pop(0)) File "D:\Projects\Python Project\venv\lib\site-packages\kivy\base.py", line 302, in post_dispatch_input wid.dispatch('on_touch_up', me) File "kivy\_event.pyx", line 731, in kivy._event.EventDispatcher.dispatch File "D:\Projects\Python Project\venv\lib\site-packages\kivymd\uix\behaviors\ripple_behavior.py", line 296, in on_touch_up return super().on_touch_up(touch) File "D:\Projects\Python Project\venv\lib\site-packages\kivymd\uix\button.py", line 981, in on_touch_up return super().on_touch_up(touch) File "D:\Projects\Python Project\venv\lib\site-packages\kivy\uix\behaviors\button.py", line 179, in on_touch_up self.dispatch('on_release') File "kivy\_event.pyx", line 727, in kivy._event.EventDispatcher.dispatch File "kivy\_event.pyx", line 1307, in kivy._event.EventObservers.dispatch File "kivy\_event.pyx", line 1191, in kivy._event.EventObservers._dispatch File "D:\Projects\Python Project\venv\lib\site-packages\kivy\lang\builder.py", line 55, in custom_callback exec(__kvlang__.co_value, idmap) File "D:\Projects\Python Project\Kivy Training\ui1.kv", line 53, in <module> app.show_result() File "D:\Projects\Python Project\Kivy Training\card.py", line 56, in show_result self.root.ids.welcome_label.text = f"{sum(self.selected_cards)}" File "kivy\properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__ AttributeError: 'super' object has no attribute '__getattr__' Process finished with exit code 1
修复后的kv代码
MyScreenManager: Card1: name: "first_screen" MDCard: size_hint: None, None size: 300, 400 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 25 spacing: 25 orientation: "vertical" MDLabel: text: "Hello" halign: "center" MDRoundFlatButton: text: "Yes" pos_hint: {"center_x": 0.5} on_press: app.append(1) on_release: app.root.current = "second_screen" MDRoundFlatButton: text: "No" pos_hint: {"center_x": 0.5} on_release: app.root.current = "second_screen" Card2: name: "second_screen" MDCard: size_hint: None, None size: 300, 400 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 25 spacing: 25 orientation: "vertical" MDLabel: text: "World" halign: "center" MDRoundFlatButton: text: "Yes" pos_hint: {"center_x": 0.5} on_press: app.append(2) on_release: app.root.current = "third_screen" app.show_result() MDRoundFlatButton: text: "No" pos_hint: {"center_x": 0.5} on_release: app.root.current = "third_screen" Card3: name: "third_screen" MDCard: size_hint: None, None size: 300, 400 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 25 spacing: 25 orientation: "vertical" MDLabel: id: welcome_label text: "Three" halign: "center"
核心原因与解答
这个错误并非因「退出第一个屏幕后才创建第二个屏幕」导致,本质是**ids的作用域与ScreenManager的组件加载逻辑问题**:
ids作用域限制:原kv代码中,welcome_label的id定义在<Card3>的类规则里,属于Card3这个Screen实例的内部ids集合,而非根节点MyScreenManager的ids。当你通过self.root.ids.welcome_label访问时,根节点的ids中不存在该控件,直接触发KeyError,进而引发Kivy包装后的AttributeError。ScreenManager的懒加载逻辑:ScreenManager默认采用懒加载策略,仅渲染当前激活的Screen,未激活的Screen内部组件不会被初始化,其
ids自然无法被根节点访问。原代码中调用show_result时,third_screen还未被激活,所以welcome_label根本未被创建,更无法通过根节点的ids获取。
修复后的kv代码将三个Screen的布局直接嵌套在MyScreenManager下,相当于强制ScreenManager在初始化时就创建所有Screen的完整组件树,此时Card3的welcome_label被提前初始化,其id可被根节点的ids捕获,因此能正常访问。
替代修复方案(保留类规则写法)
如果不想修改kv的结构,可通过ScreenManager的get_screen方法先获取目标Screen实例,再访问其内部ids:
def show_result(self): # 获取third_screen实例 third_screen = self.root.get_screen("third_screen") # 访问该Screen内部的welcome_label third_screen.ids.welcome_label.text = f"{sum(self.selected_cards)}"
内容的提问来源于stack exchange,提问作者StevenHaven

