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

修复Kivy异步程序中的AttributeError及移除弃用警告

问题修复与弃用警告移除方案

错误原因分析

你遇到的AttributeError核心原因:

  1. async_run是Kivy App类的专属方法,你错误地在MainLayout(Widget子类)实例中调用了它。
  2. MainLayout未正确关联KV文件中的控件,导致通过self.root.ids无法访问目标控件。
  3. 使用了已弃用的asyncio.ensure_future方法,触发弃用警告。

修复后的完整代码

"""Example shows the recommended way of how to run Kivy with the Python built
in asyncio event loop as just another async coroutine.
"""
import asyncio
import warnings

from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.widget import Widget

# 移除所有弃用警告
warnings.filterwarnings("ignore", category=DeprecationWarning)

Builder.load_string('''
<MainLayout>:
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            ToggleButton:
                id: btn1
                group: 'a'
                text: 'Sleeping'
                allow_no_selection: False
                on_state: if self.state == 'down': label.status = self.text
            ToggleButton:
                id: btn2
                group: 'a'
                text: 'Swimming'
                allow_no_selection: False
                on_state: if self.state == 'down': label.status = self.text
            ToggleButton:
                id: btn3
                group: 'a'
                text: 'Reading'
                allow_no_selection: False
                state: 'down'
                on_state: if self.state == 'down': label.status = self.text
        Label:
            id: label
            status: 'Reading'
            text: 'Beach status is "{}"'.format(self.status)
''')

class MainLayout(Widget):
    other_task = None

    async def waste_time_freely(self):
        """异步任务:周期性打印状态并自动切换按钮"""
        try:
            i = 0
            while True:
                if self.ids.get('label'):
                    status = self.ids.label.status
                    print(f'{status} on the beach')

                    if self.ids.btn1.state != 'down' and i >= 2:
                        i = 0
                        print('Yawn, getting tired. Going to sleep')
                        self.ids.btn1.trigger_action()

                i += 1
                await asyncio.sleep(2)
        except asyncio.CancelledError as e:
            print('Wasting time was canceled', e)
        finally:
            print('Done wasting time')

class AsyncApp(App):
    def build(self):
        return MainLayout()

    async def app_func(self):
        """整合Kivy运行与异步任务到asyncio事件循环"""
        main_layout = self.root
        main_layout.other_task = asyncio.create_task(main_layout.waste_time_freely())
        
        try:
            await self.async_run()
            print('App done')
        finally:
            main_layout.other_task.cancel()
            await main_layout.other_task

if __name__ == '__main__':
    # 使用Python 3.7+推荐的asyncio.run管理事件循环
    asyncio.run(AsyncApp().app_func())

关键修复点说明

  1. 修正async_run调用主体:
    将app_func移至AsyncApp类中,确保调用async_run的是App实例,符合Kivy API规范。

  2. 关联KV与MainLayout:
    修改KV文件为<MainLayout>:开头的规则,让KV直接作用于MainLayout类,这样就能通过self.ids直接访问KV中定义的控件,无需错误使用self.root。

  3. 替换弃用的asyncio API:

    • 用asyncio.create_task替代已弃用的asyncio.ensure_future。
    • 用asyncio.run替代get_event_loop+run_until_complete的旧写法,自动完成事件循环的创建、运行与关闭。

移除弃用警告的方法

在代码开头添加以下代码,可过滤所有DeprecationWarning类型的警告:

import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

如果需要精准过滤特定模块的警告,可添加module参数:

# 只过滤Kivy的弃用警告
warnings.filterwarnings("ignore", category=DeprecationWarning, module="kivy")
# 只过滤asyncio的弃用警告
warnings.filterwarnings("ignore", category=DeprecationWarning, module="asyncio")

内容的提问来源于stack exchange,提问作者f22daniel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:45:31