2
\$\begingroup\$

I have written a fairly simple bot that provides information or additional choice based on the user's query. It runs well and does the job, however, I was wondering how can I optimize my code and use the telebot better?

Currently the main action happens in the query handler and something tells me that I am missing possible efficiency gains (when I will attempt to build more choices for example). Below is the code, simplified for demonstration purposes:

import telebot
from telebot import types

token = bottoken

bot = telebot.TeleBot(token)

@bot.message_handler(commands=['start'])
def welcome(message):

    # here i give the main choice that is always visible to the user

    markup = types.ReplyKeyboardMarkup(resize_keyboard=False)
    item1 = types.KeyboardButton("Button1")
    item2 = types.KeyboardButton("Button2")

    markup.add(item1, item2)

    bot.send_message(message.chat.id, "Welcome message".format(message.from_user, bot.get_me()),
        parse_mode='html', reply_markup=markup)


@bot.message_handler(content_types=['text'])
def main_choice(message):

    # here i develop each of the main choices and redirect to the callback handler

    if message.text == 'Button1':

        # Forward to callback handler

            markup = types.InlineKeyboardMarkup()
            item1 = types.InlineKeyboardButton("Yes", callback_data = 'demo_yes')
            item2 = types.InlineKeyboardButton("No", callback_data = 'demo_no')

            markup.add(item1, item2)

            bot.send_message(message.chat.id, 'Some text', reply_markup=markup)


    elif message.text == 'Button2':

        # some logic

    else :
        bot.send_message(message.chat.id, 'Sorry, i dont understand. You can use /help to check how i work')


@bot.callback_query_handler(func=lambda call: True)
def tempo(call):

    # here a handle the queries launched both by main buttons and the inline keyboard 


    if call.data == "demo_yes":

        keyboard = types.InlineKeyboardMarkup()
        item1 = types.InlineKeyboardButton("Text1", callback_data = 'call1')
        item2 = types.InlineKeyboardButton("Text2", callback_data = 'call2')
        keyboard.add(item1,item2)

        bot.send_message(call.message.chat.id, 'message', reply_markup = keyboard)

    elif call.data == "demo_no":

        kkeyboard = types.InlineKeyboardMarkup()
        item1 = types.InlineKeyboardButton("Text3", callback_data = 'call3')
        item2 = types.InlineKeyboardButton("Text4", callback_data = 'call4')
        keyboard.add(item1,item2)

        bot.send_message(call.message.chat.id, 'message', reply_markup = keyboard)

    if call.data == "call1":

        keyboard = types.InlineKeyboardMarkup()
        item1 = types.InlineKeyboardButton("Text5", callback_data = 'another_call1')
        item2 = types.InlineKeyboardButton("Text6", callback_data = 'another_call2')
        keyboard.add(item1,item2)

        bot.send_message(call.message.chat.id, 'message', reply_markup = keyboard)

    elif call.data == "call2":

        kkeyboard = types.InlineKeyboardMarkup()
        item1 = types.InlineKeyboardButton("Text7", callback_data = 'another_call3')
        item2 = types.InlineKeyboardButton("Text8", callback_data = 'another_call4')
        keyboard.add(item1,item2)

        bot.send_message(call.message.chat.id, 'message', reply_markup = keyboard)
\$\endgroup\$
1
  • 3
    \$\begingroup\$ "Below is the code, simplified for demonstration purposes" Next time, please don't simplify the code. We can handle big pieces of code, but we'd be wasting your and our time by providing a review that turns out to be non-applicable to your actual code because that happens to look slightly different. \$\endgroup\$
    – Mast
    Apr 29, 2021 at 12:06

1 Answer 1

1
\$\begingroup\$

From my point of view you can use a visitor pattern for this with a simple dictionary, specially for your operations, here is a small example:

Insead of this

@bot.callback_query_handler(func=lambda call: True)
def tempo(call):

    # here a handle the queries launched both by main buttons and the inline keyboard 


    if call.data == "demo_yes":

        keyboard = types.InlineKeyboardMarkup()
        ......

Use the following

tempo_operations = {"demo_yes" : demo_yes_function,
                    "demo_no" : demo_no_function, 
                    ....}

@bot.callback_query_handler(func=lambda call: True)
def tempo(call):

    if call.data in tempo_operations:
        tempo_operations[call.data]()
    else:
        print("Operation not supported")

Hope you can get the idea :)

\$\endgroup\$
2
  • \$\begingroup\$ That's not a visitor pattern, it's a lookup table. Since the OP is looking for efficiency, a call to dict.get would be preferable to a call to both __contains__ and __getitem__. \$\endgroup\$
    – Andreas T
    Mar 15, 2021 at 19:58
  • 1
    \$\begingroup\$ While I agree on the fact that it's not exactly a visitor pattern, the proposed solution certainly answers OP's concern regarding "I am missing possible efficiency gains (when I will attempt to build more choices for example)" \$\endgroup\$
    – IEatBagels
    Apr 29, 2021 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.