如何在Python中从外部文件动态添加函数至字典供调用?
嘿,这个需求其实和Django自动识别视图的思路非常像,咱们可以通过动态模块导入+装饰器注册的组合来实现,完美解决跨文件的命令自动收集问题,下面是具体的实现步骤:
完整实现方案
1. 先做一个命令注册中心
首先创建一个command_registry.py文件,用来维护所有命令的字典,同时提供装饰器标记哪些函数是“命令”:
# command_registry.py # 全局命令字典,key是命令名,value是对应的函数 commands = {} def command(name=None): """装饰器:标记函数为命令,并注册到命令字典""" def decorator(func): # 如果用户没指定命令名,就用函数本身的名字 cmd_name = name or func.__name__ # 把函数注册到字典里 commands[cmd_name] = func return func return decorator
2. 搭建commands文件夹结构
创建一个名为commands的文件夹,记得在里面放一个空的__init__.py文件(让Python把它识别为包)。然后你就可以在里面随便加.py文件了,比如:
示例1:greetings.py
# commands/greetings.py from command_registry import command # 用函数名作为命令名 @command() def hello(name): return f"Hello, {name}!" # 自定义命令名为say_hi @command("say_hi") def hi(): return "Hi there!"
示例2:calculations.py(新增的文件)
# commands/calculations.py from command_registry import command @command() def add(a, b): return int(a) + int(b) @command() def multiply(a, b): return int(a) * int(b)
3. 写一个自动加载器
接下来需要一个加载器,启动时自动导入commands文件夹下的所有.py文件,这样装饰器就能自动把函数注册到字典里。创建command_loader.py:
# command_loader.py import os import importlib def load_commands(): """自动导入commands文件夹下的所有模块""" # 获取commands文件夹的绝对路径 commands_dir = os.path.join(os.path.dirname(__file__), "commands") # 遍历文件夹里的所有文件 for filename in os.listdir(commands_dir): # 只处理.py文件,排除__init__.py和临时文件 if filename.endswith(".py") and filename != "__init__.py": # 构造模块名(比如commands.greetings) module_name = f"commands.{filename[:-3]}" # 动态导入模块 importlib.import_module(module_name)
4. 主程序调用逻辑
最后写主文件main.py,加载所有命令后,就可以接收用户输入来调用了:
# main.py from command_registry import commands from command_loader import load_commands def main(): # 启动时先加载所有命令 load_commands() print("命令系统已启动,输入命令格式:命令名 参数1 参数2...(输入q退出)") while True: user_input = input("> ").strip() if user_input.lower() == "q": print("退出程序") break if not user_input: continue # 拆分命令名和参数 parts = user_input.split() cmd_name = parts[0] args = parts[1:] # 执行命令 if cmd_name in commands: try: result = commands[cmd_name](*args) print(f"✅ 执行结果:{result}") except TypeError as e: print(f"❌ 参数错误:{e}") else: print(f"❌ 未知命令,可用命令:{', '.join(commands.keys())}") if __name__ == "__main__": main()
额外小贴士
- 新增
.py文件后,重启主程序就能自动加载新命令;如果想要热加载(不用重启),可以在主循环里定期调用load_commands(),但要注意在加载前清空commands字典,避免重复注册。 - 命令函数的参数要和用户输入的参数数量匹配,或者可以用
*args来处理可变参数,提升容错性。 - 可以给装饰器加更多功能,比如命令描述、参数校验等,让系统更健壮。
内容的提问来源于stack exchange,提问作者WagnerAlbJr
相关产品推荐
相关产品推荐

