使用TeleBot的callback_query_handler双过滤器存状态遇NoneType错误
问题:TeleBot callback_query_handler中使用state过滤器时,retrieve_data返回None导致TypeError
在使用pyTelegramBotAPI的callback_query_handler时,同时设置func和自定义state过滤器存储状态,触发TypeError: 'NoneType' object does not support item assignment,报错行是data['model'] = call.data,不清楚为什么data是NoneType。
相关代码:
... state_storage = StateMemoryStorage() MODELS = ['ROAD', 'SPORTTOURIST'] MARKS = ['YAMAHA', 'HONDA'] class MyStates(StatesGroup): model = State() mark = State() def models_motorcycle(): return telebot.types.InlineKeyboardMarkup( keyboard=[ [ telebot.types.InlineKeyboardButton(MODELS[0], callback_data=MODELS[0]), telebot.types.InlineKeyboardButton(MODELS[1], callback_data=MODELS[1]), ] ] ) @bot.message_handler(commands=['start']) def start_filter(message): bot.set_state(message.from_user.id, MyStates.model, message.chat.id) bot.send_message(message.chat.id, 'Select motorcycle model', reply_markup=models_motorcycle()) @bot.callback_query_handler(func=lambda call: call.data in MODELS, state=MyStates.model) def callback_query_model(call): bot.set_state(call.from_user.id, MyStates.mark, call.message.chat.id) with bot.retrieve_data(call.message.from_user.id, call.message.chat.id) as data: # print(f'trying to save model data {call.data}') data['model'] = call.data bot.send_message(call.message.chat.id, 'Select motorcycle mark', reply_markup=marks_motorcycle())
错误原因
你在回调函数里先切换了状态(bot.set_state(..., MyStates.mark)),然后再调用retrieve_data(),此时retrieve_data默认获取的是当前活跃状态(也就是刚切换的MyStates.mark)的数据,但这个新状态还没有初始化任何数据,所以返回None,导致赋值时抛出错误。
修复方案
有两种可行的修复方式:
方式1:先保存数据,再切换状态
调整代码顺序,先获取当前状态(MyStates.model)的数据并保存,之后再切换到新状态:
@bot.callback_query_handler(func=lambda call: call.data in MODELS, state=MyStates.model) def callback_query_model(call): # 先获取当前状态(model)的数据并保存 with bot.retrieve_data(call.from_user.id, call.message.chat.id) as data: data['model'] = call.data # 再切换到mark状态 bot.set_state(call.from_user.id, MyStates.mark, call.message.chat.id) bot.send_message(call.message.chat.id, 'Select motorcycle mark', reply_markup=marks_motorcycle())
方式2:retrieve_data时指定要获取的状态
如果需要在切换状态后获取之前状态的数据,可以在retrieve_data中指定state参数:
@bot.callback_query_handler(func=lambda call: call.data in MODELS, state=MyStates.model) def callback_query_model(call): bot.set_state(call.from_user.id, MyStates.mark, call.message.chat.id) # 指定获取MyStates.model状态下的数据 with bot.retrieve_data(call.from_user.id, call.message.chat.id, state=MyStates.model) as data: data['model'] = call.data bot.send_message(call.message.chat.id, 'Select motorcycle mark', reply_markup=marks_motorcycle())
内容的提问来源于stack exchange,提问作者Donsky1
相关产品推荐
相关产品推荐

