【问题标题】:Python Telegram bot adding handlers from listPython Telegram bot 从列表中添加处理程序
【发布时间】:2018-08-25 02:39:20
【问题描述】:

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

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

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

【问题讨论】:

    标签: python telegram telegram-bot


    【解决方案1】:

    tldr;

    此问题不属于电报机器人或python-telegram-bot lib。
    这只是 Python 语言的一个功能
    这背后的原因有点类似于著名的lambda functions in list comprehension 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 关于闭包。

    【讨论】:

      猜你喜欢
      • 2021-06-25
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      • 2022-08-22
      • 2022-11-12
      相关资源
      最近更新 更多