如何存储Python的函数,使其在使用的全局变量被更改后函数的输出也不会被改变?

问题遇到的现象和发生背景

这几天在搞PyQt6的插件化开发,做到插件管理器的地方时出现的问题,点不同插件菜单现实的插件信息都是最后一个插件的

问题相关代码
from libs.windows.Calculator import *
from PyQt6.QtGui import *
import importlib
import glob

plugins = {}
for i in glob.glob("plugins/*.py"):
    plugin_file_name = i.replace("\\", ".").replace(".py", "")
    if "__init__" not in plugin_file_name:
        plugin = importlib.import_module(plugin_file_name)
        plugins[plugin_file_name.replace("plugins.", "")] = plugin

functions = {}  # FIXME: 问题出在这,我以为用字典存储函数,函数使用的全局变量被更改后函数是不会变的,但是我错了,这就导致信息函数指向的插件信息全是最后一个插件的
for i in plugins:
    def info():
        author = getattr(plugins[i], "__author__", "Unknown")
        version = getattr(plugins[i], "__version__", "1.0.0")
        if plugins[i].__doc__ is None:
            doc = "\nNo document\n"
        doc = plugins[i].__doc__
        QMessageBox.information(calculator, "插件信息", f"插件文件名:{i}\n插件名称:{plugins[i].__name__}\n插件作者:{author}\n插件版本:{version}\n{doc}")
    functions[i] = info

menus = {}
for i in plugins:
    plugin_menu = QMenu(plugins[i].__name__, calculator.ui.plugins_menu)
    plugin_menu.setObjectName(i)
    calculator.ui.plugins_menu.addMenu(plugin_menu)
    menus[i] = plugin_menu

actions = {}
for i in plugins:
    plugin_menu_action = QAction("插件信息", menus[i])
    plugin_menu_action.setObjectName(menus[i].objectName() + "_action")
    plugin_menu_action.triggered.connect(functions[i])
    actions[i] = plugin_menu_action

for i in plugins:
    menus[i].addAction(actions[i])
运行结果及报错内容

所有插件菜单点击后显示的插件信息全都是最后一个的

我的解答思路和尝试过的方法

我之前的思路是使用字典或列表存储函数,但是我发现函数使用的全局变量被更改后,函数即使被存储在字典中也是会改变的,所以我遍历完插件信息字典后,所有函数指向的插件信息就全是最后一个插件的了

我想要达到的结果

点击不同的插件菜单,显示对应插件的信息

解决了,写一个闭包就好了
附上代码(虽然写得很难看,但好歹能跑了)

from libs.windows.Calculator import *
from PyQt6.QtGui import *
import importlib
import glob

plugins = {}
for i in glob.glob("plugins/*.py"):
    plugin_file_name = i.replace("\\", ".").replace(".py", "")
    if "__init__" not in plugin_file_name:
        plugin = importlib.import_module(plugin_file_name)
        plugins[plugin_file_name.replace("plugins.", "")] = plugin

def info():
    def _info(i):
        if plugins[i].__doc__ is None:
            doc = "\nNo document\n"
        doc = plugins[i].__doc__
        return {
            "name": plugins[i].__name__,
            "author": getattr(plugins[i], "__author__", "Unknown"),
            "version": getattr(plugins[i], "__version__", "1.0.0"),
            "document": doc,
            "show": lambda: QMessageBox.information(calculator, "插件信息", f"插件文件名:{i}\n插件名称:{plugins[i].__name__}\n插件作者:{getattr(plugins[i], '__author__', 'Unknown')}\n插件版本:{getattr(plugins[i], '__version__', '1.0.0')}\n{doc}")
        }
    functions = {}
    for i in plugins:
        functions[i] = _info(i)
    return functions

menus = {}
for i in info():
    plugin_menu = QMenu(info()[i]["name"], calculator.ui.plugins_menu)
    plugin_menu.setObjectName(i)
    calculator.ui.plugins_menu.addMenu(plugin_menu)
    menus[i] = plugin_menu

actions = {}
for i in info():
    plugin_menu_action = QAction("插件信息", menus[i])
    plugin_menu_action.setObjectName(menus[i].objectName() + "_action")
    plugin_menu_action.triggered.connect(info()[i]["show"])
    actions[i] = plugin_menu_action

for i in info():
    menus[i].addAction(actions[i])

plugins是个字典
遍历的时候应该
for k,v in plugins.items():
你这for i in plugins是个什么语法
而且还能plugins[i]这样用?你plugins到底是个什么,是不是一会是dict一会是list
-=-==-
还有,你这是个典型的闭包问题
info应该有参数,i应该作为参数传进来
否则info最后肯定是只有一个值,而不是对应每个i都有一个对应的info