首页 > 解决方案 > Python Telegram bot 从列表中添加处理程序

问题描述

我在运行时添加命令处理程序时遇到问题,这是一个示例:

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 打印。我想也许该函数每次都存储在内存中的同一个位置,并尝试将回调存储在一个列表中,但它没有帮助。

关于如何做到这一点的任何想法?

标签: pythontelegramtelegram-bot

解决方案


tldr;

此问题不属于电报机器人或python-telegram-botlib。
这只是 Python 语言的一个特性
这背后的原因有点类似于列表理解python 行为中著名的 lambda 函数。


测试用例

考虑这个稍微简化的脚本版本:

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


解释

您会得到相同的结果,因为您通过定义内部循环并在 func 本身内部使用来创建闭包。dummy_funcforitems[i][1]

问题是您可能不希望仅在实际执行此特定函数时dummy_func才会引用变量。i

并且由于它是在for循环结束后执行的,所以它的值i是它在循环中的最后一个值。因此,您的所有函数都引用 的相同值i,即2,并且在这种情况下items[i][1]将始终3如此。


链接

关于 Python 中的作用域和闭包的好文章。
GitHub关于闭包的要点。


推荐阅读