使用pyTelegramBotAPI开发Telegram Bot时遭遇TypeError错误求助
问题说明
使用pyTelegramBotAPI开发Telegram Bot时,触发TypeError: 'NoneType' object is not callable错误,该错误发生在send_to_club_page()函数发送"hello"之后,尝试改用带lambda的消息处理器也无法解决。
错误根源
问题出在get_search_url函数中的这一行:
bot.register_next_step_handler(message, return_search(message, data))
这里直接调用了return_search(message, data)函数,而不是传入函数对象。由于return_search函数没有显式返回值(默认返回None),register_next_step_handler接收的第二个参数是None。当Bot尝试执行这个下一步处理器时,就会触发"NoneType对象不可调用"的错误。
修复方案
需要将函数调用改为传递函数对象,同时保留所需参数。可以通过两种方式实现:
方式1:使用lambda表达式包装
修改get_search_url中的对应代码:
bot.register_next_step_handler(message, lambda msg: return_search(msg, data))
lambda表达式会创建一个新的函数对象,接收消息参数msg后,再调用return_search并传递正确的参数。
方式2:使用functools.partial(推荐,更清晰)
先导入functools模块,再用partial绑定参数:
import functools # 在get_search_url函数中 bot.register_next_step_handler(message, functools.partial(return_search, data=data))
partial会生成一个绑定了data参数的新函数,符合register_next_step_handler对函数参数的要求。
修正后的完整代码
import telebot from telebot import types from scraper import get_clubs_from_search import functools # 新增导入 bot = telebot.TeleBot('###') @bot.message_handler(commands=['start']) def start(message): msg = f"""Hello, <b>{message.from_user.first_name}</b> \n/help for commands list \n/search for search options""" bot.send_message(message.chat.id, msg, parse_mode='html') @bot.message_handler(commands=['help']) def help(message): msg = f"""You can use the following commands: \n/search to search for a team or a player""" bot.send_message(message.chat.id, msg, parse_mode='html') @bot.message_handler(commands=['search']) def search(message): markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) player_search = types.KeyboardButton("Search for a player") team_search = types.KeyboardButton("Search for a team") markup.add(player_search, team_search) bot.send_message(message.chat.id, 'Choose an option:', reply_markup=markup) @bot.message_handler(func=lambda message: message.text in ['Search for a player', 'Search for a team']) def team_search(message): if message.text == 'Search for a team': msg = bot.send_message(message.chat.id, "Type the name of the team", reply_markup=types.ForceReply(selective=False)) bot.register_next_step_handler(msg, get_search_url) def get_search_url(message): """Taking user request and forming a search url. then calling get_clubs_from_search """ search_request = message.text.split() final_query = "" for i in range(len(search_request)): if i != (len(search_request)-1): final_query += f"{search_request[i]}+" else: final_query += f"{search_request[i]}" url = f"https://www.transfermarkt.com/schnellsuche/ergebnis/schnellsuche?query={final_query}" data = get_clubs_from_search(url) # 修复此处:使用lambda包装 bot.register_next_step_handler(message, lambda msg: return_search(msg, data)) # 或者用functools.partial: # bot.register_next_step_handler(message, functools.partial(return_search, data=data)) def return_search(message, data): """Presenting dataframe to user and asking to choose a team""" msg = "Please choose the team:\n\n" markup = types.ReplyKeyboardMarkup(True) for i in range(len(data)): msg += f"""{i+1}. {data.loc[i]['club_names']} from {data.loc[i]['country_names']}\n""" markup.add(types.KeyboardButton(str(i+1))) # 注意:转成字符串避免类型问题 final_message = bot.send_message(message.chat.id, msg, reply_markup=markup) bot.register_next_step_handler(final_message, send_to_club_page, data) def send_to_club_page(message, data): msg = "hello" bot.send_message(message.chat.id, msg, parse_mode='html') while True: bot.polling(none_stop=True, timeout=5)
额外注意:return_search中创建KeyboardButton时,需将整数i+1转为字符串str(i+1),避免潜在类型错误。
额外说明
send_to_club_page函数本身无问题,只要确保它被正确传递给register_next_step_handler即可。之前的错误完全是因为get_search_url中错误地传递了函数执行结果而非函数对象导致的。
内容的提问来源于stack exchange,提问作者Kapytal

