Python Telegram 机器人从列表中添加处理程序

Python Telegram bot adding handlers from list

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

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

关于如何做到这一点有什么想法吗?

tldr;

此问题不属于电报机器人或 python-telegram-bot 库。
它只是 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


说明

你会得到相同的结果,因为你通过在 for 循环内定义 dummy_func 并在 func 本身内使用 items[i][1] 创建了一个 闭包

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

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


链接

Nice article 关于 Python 中的作用域和闭包。
GitHub gist 关于关闭。