vlizana
vlizana

Reputation: 3232

Python Telegram bot adding handlers from list

I'm having trouble adding command handlers on the run, here's an example:

from telegram.ext import Updater, CommandHandler

updater = Updater(token)
items = [
    ('a', 1),
    ('b', 2),
    ('c', 3)
]

for i in range(len(items)):
    def dummy_func(bot, update):
        print(items[i][1])

    updater.dispatcher.add_handler(
        CommandHandler(items[i][0], dummy_func)
    )

updater.start_polling()

I would expect /a to print 1 in my console for example, but instead 3 is printed for a, b or c. I thought maybe the function is stored every time in the same spot in memory and tried storing the callbacks in a list but it didn't help.

Any ideas on how to do this?

Upvotes: 1

Views: 1285

Answers (1)

Ivan Vinogradov
Ivan Vinogradov

Reputation: 4483

tldr;

This problem does not belong to telegram bots or python-telegram-bot lib.
It's just a feature of Python language.
The reason behind that is somewhat similar to famous lambda functions in list comprehension python behaviour.


Test case

Consider this slightly simplified version of your script:

items = [
    ('a', 1),
    ('b', 2),
    ('c', 3)
]

handlers = []  # think of dispatcher handlers as a list
for i in range(len(items)):
    def dummy_func():  # <--- closure
        print(items[i][1])  

    handlers.append(dummy_func)  # somewhat similar to dispatcher.add_handler()

for f in handlers:  # let's see the results
    f()

It outputs exactly the same result as you got:

3
3
3


Explanation

You get same results because you create a closure by defining dummy_func inside for loop and using items[i][1] inside the func itself.

The problem is that you probably don't expect that dummy_func will reference variable i only when this particular function is actually being executed.

And since it is executed after for loop is finished, the value of i is its last value in loop. So all your functions refer to the same value of i, which is 2, and items[i][1] will always be 3 in this case.


Links

Nice article about scoping and closures in Python.
GitHub gist about closures.

Upvotes: 1

Related Questions