Is there a way to access a variable from inside a function without passing it as an argument?

Question:

I’m trying to write a telegram bot, that uses inline keyboards to make criteria for selection in a step by step way. And I want the last step of this to be a message telling me what are the criteria selected. Normally I would return the string value from one function and pass it into another, but I’m new to telegram bots and don’t know how to do it correctly here. So i thought if i could somehow modify a variable inside a function and then make use of it inside another function that would solve my problem, but unfortunately I didn’t manage to find anything that worked for me.

from aiogram import Bot, Dispatcher, executor, types
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton

button1 = InlineKeyboardButton(text="Criteria1", callback_data="Never")
button2 = InlineKeyboardButton(text="Criteria2", callback_data="Gonna")
button3 = InlineKeyboardButton(text="Criteria3", callback_data="Give")
button4 = InlineKeyboardButton(text="Selected Criteria", callback_data="You")
keyboard_inline = InlineKeyboardMarkup().add(button1, button4)
keyboard_inline2 = InlineKeyboardMarkup().add(button2, button4)
keyboard_inline3 = InlineKeyboardMarkup().add(button3, button4)
keyboard_inline4 = InlineKeyboardMarkup().add(button4)


bot = Bot(token="")
dp = Dispatcher(bot)
selected_criteria = ""


@dp.message_handler(commands=['start', 'help'])
async def welcome(message: types.Message):
    selected_criteria = "Nothing was selected"
    await message.reply("Welcome Choose 1st Criteria", reply_markup=keyboard_inline)


@dp.callback_query_handler(text=["Never", "Gonna", "Give", "You"])
async def criteria_selection(call: types.CallbackQuery):
    if call.data == "Never":
        selected_criteria = "Criteria1 was selected"
        await call.message.reply("Choose 2nd Criteria", reply_markup=keyboard_inline2)
    if call.data == "Gonna":
        selected_criteria = "Criteria2 was selected"
        await call.message.reply("Choose 3rd Criteria", reply_markup=keyboard_inline3)
    if call.data == "Give":
        selected_criteria = "Criteria3 was selected"
        await call.message.reply("End Selection", reply_markup=keyboard_inline4)
    if call.data == "You":
        await call.message.reply(selected_criteria)
    await call.answer()


executor.start_polling(dp)

Basically i want to know if there is some way for me to save changes to variable "selected_criteria" and make use of those changes in other functions.

selected_criteria = ""


def function1():
    selected_criteria = "criteria1"
    
    
def function2():
    selected_criteria = "criteria2"
    

function1()
function2()
print(selected_criteria)

Maybe there is a more natural way to do it with telegram bots if so please tell me.

Asked By: Aomori 23

||

Answers:

Not sure if this is a standard pattern, but it seems like you could make these handler functions instance methods (so they can share instance attributes) and register them in __init__:

class Handler:
    def __init__(self, dp: Dispatcher):
        self.selected_criteria = ""
        dp.message_handler(
            commands=['start', 'help']
        )(self.welcome)
        dp.callback_query_handler(
            text=["Never", "Gonna", "Give", "You"]
        )(self.criteria_selection)

    async def welcome(self, message: types.Message):
        self.selected_criteria = "Nothing was selected"
        await message.reply("Welcome Choose 1st Criteria", reply_markup=keyboard_inline)

    async def criteria_selection(self, call: types.CallbackQuery):
        if call.data == "Never":
            self.selected_criteria = "Criteria1 was selected"
            await call.message.reply("Choose 2nd Criteria", reply_markup=keyboard_inline2)
        if call.data == "Gonna":
            self.selected_criteria = "Criteria2 was selected"
            await call.message.reply("Choose 3rd Criteria", reply_markup=keyboard_inline3)
        if call.data == "Give":
            self.selected_criteria = "Criteria3 was selected"
            await call.message.reply("End Selection", reply_markup=keyboard_inline4)
        if call.data == "You":
            await call.message.reply(self.selected_criteria)
        await call.answer()

bot = Bot(token="")
dp = Dispatcher(bot)
handler = Handler(dp)
Answered By: Samwise