You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Kivy ScreenManager时遭遇AttributeError错误的原因咨询

Kivy ScreenManager 中 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的组件加载逻辑问题**:

  1. ids作用域限制:原kv代码中,welcome_label的id定义在<Card3>的类规则里,属于Card3这个Screen实例的内部ids集合,而非根节点MyScreenManager的ids。当你通过self.root.ids.welcome_label访问时,根节点的ids中不存在该控件,直接触发KeyError,进而引发Kivy包装后的AttributeError。

  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:45:28