菲林迷迭香 2022-08-15 13:12 采纳率: 50%
浏览 36
已结题

如何存储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])
运行结果及报错内容

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

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

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

我想要达到的结果

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

  • 写回答

2条回答 默认 最新

  • 菲林迷迭香 2022-08-15 17:43
    关注

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

    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])
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 8月23日
  • 已采纳回答 8月15日
  • 创建了问题 8月15日

悬赏问题

  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助