如何从Experta规则引擎中提取含具体Lambda条件的规则
解决Experta规则引擎中Lambda条件的可读化提取问题
问题
使用Experta库构建规则引擎时,提取规则后发现Lambda函数仅显示内存地址(如Iris(petal_width=P(<function IrisExpert.<lambda> at 0x7fe3fd4788c8>,))),无法直观看到具体的判断条件,需要提取出包含Lambda核心逻辑的规则格式(如Iris(petal_width=P(x > 5)))。
解决方案
Experta的P(Predicate)类默认的__repr__方法不会解析Lambda的源码内容,因此需要自定义一个支持可读输出的P子类,利用inspect模块获取Lambda函数的源码文本,并重写__repr__方法来展示核心判断逻辑。
修改后的完整代码
from experta import * import pydot import inspect # 自定义支持可读输出的Predicate子类 class ReadableP(P): def __repr__(self): if callable(self.predicate): try: # 获取lambda函数的源码文本 source = inspect.getsource(self.predicate).strip() # 提取lambda的核心判断表达式 if source.startswith('lambda'): expr = source.split(':', 1)[1].strip() return f"P({expr})" return f"P({source})" except (TypeError, OSError): # 无法获取源码时使用默认输出 return super().__repr__() return super().__repr__() class Iris(Fact): """IRIS""" sepal_length = Field(float) sepal_width = Field(float) petal_length = Field(float) petal_width = Field(float) class Species(Fact): """Species characteristics""" pass class IrisExpert(KnowledgeEngine): def __init__(self): super().__init__() self.status = None # 使用自定义的ReadableP替代原P @Rule(Iris(sepal_length=ReadableP(lambda x: x > 5), sepal_width=ReadableP(lambda x: x < 3))) def rule1(self): self.status = 'Iris Setosa' return self.declare(Species(flower='Iris Setosa')) @Rule(AND( Iris(sepal_length=ReadableP(lambda x: x > 5.5)), Iris(sepal_width=ReadableP(lambda x: x > 2.5)) )) def rule2(self): self.status = 'Iris Versicolor' return self.declare(Species(flower='Iris Versicolor')) @Rule(AND( Iris(petal_length=ReadableP(lambda x: x > 4.8)), Iris(petal_width=ReadableP(lambda x: x > 1.8)) )) def rule3(self): self.status = 'Iris Virginica' return self.declare(Species(flower='Iris Virginica')) def execute_fuc(key): if key == 'rule1': print('executing rule-1') engine.rule1() elif key == 'rule2': print('executing rule-2') engine.rule2() else: print('executing rule-3') engine.rule3() # 创建规则引擎实例 engine = IrisExpert() engine.reset() # 创建Pydot图 graph = pydot.Dot(graph_type='digraph', comment='IRIS Expert Rules') # 为每个规则添加节点 for rule_instance in engine.get_rules(): quality = rule_instance() # 现在repr会显示可读的Lambda条件 qual_node = pydot.Node(repr(quality)) graph.add_node(qual_node) for rule in rule_instance: print('rule_format: ', repr(rule))
说明
- ReadableP类:继承自Experta的
P类,重写__repr__方法,通过inspect.getsource获取Lambda函数的源码,提取出:后的核心判断表达式,输出为P(表达式)的格式。 - 异常处理:当Lambda函数无法获取源码(如在交互式环境中定义)时,会 fallback 到原
P类的默认输出,避免报错。 - 规则替换:只需将原规则中的
P替换为ReadableP,即可实现规则提取时的可读化输出。
内容的提问来源于stack exchange,提问作者merkle
相关产品推荐
相关产品推荐

