Python 在递归函数调用中收集乘法返回值(自动nfa处理)

Python 在递归函数调用中收集乘法返回值(自动nfa处理),python,recursion,automaton,Python,Recursion,Automaton,我正在编写一个NFA(非确定性有限自动机)类,它应该解析给定的输入并返回所有可能的跟踪(从初始状态到最终状态的路径)。最后,我想计算给定自动机的模糊度 不幸的是,我无法正确地收集方法的返回。此版本的代码返回None,使用yield稍微修改的代码只返回第一条路径 这个问题似乎有些模糊,但我希望有人能给我一个正确方向的提示 提前谢谢 NFA类(对象): __插槽\uuuux=[ “国家”, “字母表”, “过渡”, “初始状态”, “最终国家”, ] # # #-----初始化-----------

我正在编写一个NFA(非确定性有限自动机)类,它应该解析给定的输入并返回所有可能的跟踪(从初始状态到最终状态的路径)。最后,我想计算给定自动机的模糊度

不幸的是,我无法正确地收集方法的返回。此版本的代码返回
None
,使用
yield
稍微修改的代码只返回第一条路径

这个问题似乎有些模糊,但我希望有人能给我一个正确方向的提示

提前谢谢

NFA类(对象):
__插槽\uuuux=[
“国家”,
“字母表”,
“过渡”,
“初始状态”,
“最终国家”,
]
#
#
#-----初始化-----------
#
定义初始化__(
自己
国家:集,
字母表:集合,
过渡:dict,
初始状态:str,
最终状态:设置,
):
"""
初始化一个完整的自动机。
"""
self.states=状态
self.alphabet=字母表
self.transitions=转换
self.initial_state=初始_状态
self.final_states=最终_states
#
#
#-----过程-----------
#
def进程(self,word:str,trace:list=[])->list:
"""
检查此自动机是否接受给定字符串。
返回所有接受路径。
"""
#处理完成并返回跟踪
如果(不是单词):
打印(跟踪)
返回轨迹
#以初始状态开始处理
如果(非跟踪):
trace.append(self.initial_状态)
#获取当前状态转换
状态转换:dict=self.transitions.get(跟踪[-1],无)
#不接受输入
如果(不是状态转换):
返回错误
#迭代每个可能的转换
对于处于状态_transition.get(字[0],])的状态:
#创建新的子跟踪,附加当前状态
sub_trace:list=trace.copy()
子跟踪追加(状态)
#启动递归函数调用
self.process(word[1:],trace=sub_trace)
从automata.nfa导入nfa
配置:dict={
“状态”:['q0','q1','q2'],
字母表:[a'],
“过渡”:{
“q0”:{
‘a’:[‘q1’、‘q2’]
},
“q1”:{
'a':['q1']
}
},
“初始状态”:“q0”,
“最终状态”:[“q1”],
}
testNFA=NFA(**配置)
断言testNFA.process(“a”)=[['q0',q1'],['q0',q2']]

听起来你要求的是一个基本的、基本的。我认为这个设计混淆了一些东西

如果您
返回递归调用中的某个内容,那么数据只会返回到其直接调用方,并且需要一路返回调用链到原始范围。如果您不想使用生成器,则可能需要某种主结果列表参数,当您遇到已使用
word
且NFA处于接受状态的基本情况时,可以将
trace
的副本附加到该参数。内部函数对此非常有用,可以避免向调用方公开大量默认参数

一种可能更好的方法是使用一个函数,它避免了管理结果列表和传递返回值,并让调用方控制如何使用结果

您提到您尝试了一个生成器版本,但是递归生成器将应用于递归调用

考虑到这种方法,您显示的代码没有考虑到
最终状态
,因此根据“从初始状态到最终状态的路径”的问题描述,您的预期输出似乎不正确。我希望
[['q0',q1']]
是所需的输出,因为
“q2”
不是接受状态。但是,正如您将在下面我的代码片段中看到的那样,在这两者之间做出决定是微不足道的

作为一个实现细节,每个递归调用切片一个字符串是O(n)。您可以使用索引在所有递归调用帧共享的单个字符串中跟踪您的位置,以避免此开销。类似地,在每次调用时复制
跟踪
列表要比保留一个要推送/弹出的列表并仅在
产生
时复制它慢

当心这件事

下面是一个简单完整的示例:

from collections import namedtuple

def find_accepting_paths(nfa, word, trace=None):
    trace = trace if trace else [nfa.initial_state]

    if word:
        for state in nfa.transitions.get(trace[-1], {}).get(word[0], []):
            trace.append(state)
            yield from find_accepting_paths(nfa, word[1:], trace)
            trace.pop()
    elif trace[-1] in nfa.final_states: # or use `else` if you're sure you
                                        # don't care about accepting states
        yield trace[:]

if __name__ == "__main__":
    NFA = namedtuple("NFA", "transitions initial_state final_states")
    nfa = NFA(
        transitions={
            "q0": {
                "a": ["q1", "q2"]
            },
            "q1": {
                "a": ["q1"]
            }
        },
        initial_state="q0",
        final_states=["q1"],
    )
    print(list(find_accepting_paths(nfa, "a"))) # => [['q0', 'q1']]

谢谢你的回复。我已经完成了类示例并在断言中添加了预期的输出。非常感谢,我不知道
yield from
的功能,除了
yield
,有了这个建议,我能够快速解决我的问题。谢谢你的学术背景资料。特别是字符串切片的计算成本,这在处理高度模糊的NFA中的大型字符串时可能确实相关。我还更改了我的方法描述,它应该只处理给定的字符串并返回所有可能的路径。