Бот Python Telegram, добавляющий обработчики из списка - PullRequest
0 голосов
/ 25 августа 2018

У меня проблемы с добавлением обработчиков команд на ходу, вот пример:

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()

Я бы ожидал, например, /a напечатает 1 в моей консоли, но вместо этого 3 будет напечатано для a, b или c. Я подумал, что, возможно, функция хранится каждый раз в одном и том же месте в памяти и пытался сохранить обратные вызовы в списке, но это не помогло.

Есть идеи, как это сделать?

1 Ответ

0 голосов
/ 28 августа 2018

tldr;

Эта проблема не относится к телеграмм-ботам или python-telegram-bot lib.
Это просто функция языка Python.
Причина этого заключается в том, чточем-то похожим на известные лямбда-функции в понимании списка поведение Python.


Контрольный пример

Рассмотрим эту слегка упрощенную версию вашего скрипта:

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()

Выводит точно такой же результат, как и вы:

3
3
3


Пояснение

Вы получаете те же результаты, потому что вы создаете замыкание , определяя dummy_func внутри for цикла и используя items[i][1] внутри самого функционала.

Проблема в том, что вы, вероятно, не ожидаете, что dummy_func будет ссылаться на переменную i только тогда, когда эта конкретная функция фактически выполняется .

И поскольку он выполняется после завершения цикла for, значение i является его последним значением в цикле.Таким образом, все ваши функции ссылаются на одно и то же значение i, которое равно 2, и items[i][1] всегда будет 3 в этом случае.


Links

Хорошая статья о области видимости и замыканиях в Python.
GitHub gist о замыканиях.

...