Python 反射机制是一种在运行时检查、访问和修改对象属性和方法的能力。下面介绍下相关的模块和函数:
- 内置函数
- inspect 模块
- 插件系统示例
1. 内置函数
getattr(obj, name[, default])
: 获取对象obj
的属性或方法name
的值;hasattr(obj, name)
: 检查对象obj
是否具有属性或方法name
。返回布尔值;setattr(obj, name, value)
: 设置对象obj
的属性或方法name
的值为value
;delattr(obj, name)
: 删除对象obj
的属性或方法name
;dir(obj)
: 返回对象obj
的所有属性和方法的名称列表。
2. inspect 模块
inspect.getmembers(object[, predicate])
:用于获取对象object
中的所有属性和方法;inspect.ismodule(object)
:检查对象是否是一个模块;inspect.isclass(object)
:检查对象是否是一个类;inspect.isfunction(object)
:检查对象是否是一个函数;inspect.ismethod(object)
:检查对象是否是一个方法;inspect.isbuiltin(object)
:检查对象是否是一个内置函数或方法;inspect.isroutine(object)
:检查对象是否是函数、方法或内置函数;inspect.getmodule(object)
:返回定义对象的模块。如果对象没有模块信息,则返回None
;inspect.getsource(object)
:获取对象的源代码,如果源代码不可用则引发OSError
异常;inspect.getfile(object)
:获取对象所属模块的文件名;inspect.getmembers(object)
:获取对象的属性和方法列表;inspect.getdoc(object)
:获取对象的文档字符串;inspect.signature(object)
:返回一个Signature
对象,该对象包含了函数或方法的参数信息;inspect.getclasstree(classes[, unique])
:返回一个树形结构,表示一组类之间的继承关系;inspect.getmro(cls)
:返回一个元组,包含类cls
及其基类的方法解析顺序;inspect.getframeinfo(frame, context=1)
:返回包含帧对象信息的命名元组,用于分析调用堆栈;inspect.currentframe()
:获取当前帧对象,可用于分析调用堆栈。
3. 插件系统示例
文件架构如下。当我们在 plugins 目录下新增模块文件,系统会自行加载模块中定义的 BasePlugin 的子类,并自动调用其相关的函数。
│ main.py │ Plugin.py │ PluginManager.py │ ├─plugins │ │ PluginA.py │ │ PluginB.py │ │ PluginC.py │ └─ └─
完整示例代码:https://github.com/chinacpp/PluginManager,关键代码示例如下:
import importlib import glob import os import inspect from Plugin import BasePlugin class PluginManger: def __init__(self): self.plugins = [] def load_plugin(self, module_name): # 导入模块 module = importlib.import_module(module_name) # 获得所有满足条件类对象 def predicate(module): if not isinstance(module, type): return False if not issubclass(module, BasePlugin) or module is BasePlugin: return False return True classes = inspect.getmembers(module, predicate=predicate) return classes def load_plugins(self): # 1. 加载模块中类对象 module_names = glob.glob('plugins/*.py') my_classes = [] for mudule_name in module_names: module_name, extension = os.path.splitext(mudule_name) module_name = module_name.replace(os.path.sep, '.') classes = self.load_plugin(module_name) my_classes.extend(classes) # 2. 实例化插件对象 for _, my_class in my_classes: try: print('-----插件', my_class.__name__, '初始化-----') object = my_class() self.plugins.append(object) except Exception as error: print('Error: 插件初始化失败,原因: ', error) def process(self): for plugin in self.plugins: print('-----插件', plugin.__class__.__name__, '执行-----') plugin.enter() plugin.do() plugin.exit()