Reputation: 3232
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
Reputation: 4483
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.
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
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.
Nice article about scoping and closures in Python.
GitHub gist about closures.
Upvotes: 1