如何在python中检测无限循环
我正在学习Python3,正在做一个练习,要求编写一个Python程序,模拟/读取一个基本程序作为输入。我一直在写Python程序中应该检测无限循环的部分。以下是我目前掌握的代码:如何在python中检测无限循环,python,python-3.x,infinite-loop,Python,Python 3.x,Infinite Loop,我正在学习Python3,正在做一个练习,要求编写一个Python程序,模拟/读取一个基本程序作为输入。我一直在写Python程序中应该检测无限循环的部分。以下是我目前掌握的代码: def execute(prog): while True: location = 0 if prog[location] == len(prog) - 1: break return "success" getT = prog[locat
def execute(prog):
while True:
location = 0
if prog[location] == len(prog) - 1:
break
return "success"
getT = prog[location].split()
T = len(getT) - 1
location = findLine(prog, T)
visited = [False] * len(prog)
这里,prog是包含基本程序的字符串列表(字符串的形式为5 GOTO 30、10 GOTO 20等)
T是prog[location]中指示的目标字符串
如果BASIC程序有一个无限循环,那么我的Python程序将有一个无限循环。我知道,如果任何一行被访问两次,那么它将永远循环,我的程序将返回“无限循环”
教程助手给出的提示是“初始化访问的列表=[False]*len(prog)并在访问prog[i]时将访问的[i]更改为True。每次通过循环,访问的[]中都会更新一个值。想想如何更改列表中的单个值。然后想想如何确定访问的[]中需要更改的值。”
这就是我一直坚持的部分。如何跟踪prog中哪些字符串已被访问/循环 我不确定我是否同意两次访问一条线就证明了一个无限循环。见问题下的评论。但我可以回答实际问题 以下是提示: 教程助手给出的提示是“初始化访问的列表=[False]*len(prog)并在访问prog[i]时将访问的[i]更改为True。每次通过循环,访问的[]中都会更新一个值。想想如何更改列表中的单个值。然后想想如何确定访问的[]中需要更改的值。” 这意味着您应该有两个列表,一个包含程序,另一个包含真/假标志。第二个将命名为
已访问
,最初包含False
值
Python代码如提示所示:
visited = [False] * len(prog)
这将使用*
列表运算符“列表重复”,重复长度为1的列表,并生成长度更长的新列表
要将访问的[i]更改为True
很简单:
visited[i] = True
然后你可以这样做:
if visited[i]:
print("We have already visited line {}".format(i))
print("Infinite loop? Exiting.")
sys.exit(1)
class ProgramCode(object):
def __init__(self, statement):
self.code = statement
self.visited = False
prog = []
with open(input_basic_program_file, "rt") as f:
for line in f:
prog.append(ProgramCode(line))
请注意,我们在测试True
值时,只需说如果访问[i]:
如果访问[i]==True:,我们也可以编写,但是较短的形式就足够了,并且是Python社区的习惯。这里记录了这一习惯用语和其他习惯用语:
对于一个如此小的程序,像这样保存两个列表并不太糟糕。对于较大且复杂的程序,我更喜欢将所有内容放在一个地方。这将使用一个你可能还没有学会的“类”。大概是这样的:
if visited[i]:
print("We have already visited line {}".format(i))
print("Infinite loop? Exiting.")
sys.exit(1)
class ProgramCode(object):
def __init__(self, statement):
self.code = statement
self.visited = False
prog = []
with open(input_basic_program_file, "rt") as f:
for line in f:
prog.append(ProgramCode(line))
现在,我们没有两个列表,而是一个列表,其中每个项目都是一些基本代码和一个已访问的标志
另外,上面显示了一个显式的for
循环,该循环重复使用.append()
添加到列表中。一个有经验的Python开发人员可能会使用“列表理解”来代替,但我想让它尽可能容易理解
这是清单。如果现在看起来很奇怪,不要担心;你的班级最终会教你这个
with open(input_basic_program_file, "rt") as f:
prog = [ProgramCode(line) for line in f]
我知道Python中没有自动检测无限循环的方法,但是通过使用分治方法和测试单个函数,您可以找到有问题的函数或代码块,然后继续调试
如果Python程序输出数据,但您从未看到该输出,那么这就很好地表明您有一个无限循环。您可以在repl中测试所有函数,而不“返回”[命令提示符]的函数可能是可疑的
您可以在某种调试变量下写入输出,以便在一切正常时关闭。这可能是Python类的一个成员变量,您的代码必须随时访问该类,或者您可以使用一个模块范围的变量,如Debug=1
,并使用调试级别打印不同数量的调试信息,如1多一点、2多一点、3多一点、4多一点
例如,如果在可疑函数中打印循环计数器的值,那么最终该循环计数器将继续打印远远超过数据计数(测试记录)您曾经使用过测试。我用J.Carlos p.的部分答案和steveha给出的提示,以及使用说明给出的提示,想出了一个组合:
def execute(prog):
location = 0
visited = [False] * len(prog)
while True:
if location==len(prog)-1:
return "success"
findT = prog[location].split()
T = findT[- 1]
if visited[location]:
return "infinite loop"
visited[location] = True
location = findLine(prog, T)
从技术上讲,不可能确定程序是否有无限循环。看。如果任何一行被访问两次,那么它就会永远循环,这不是真的。如果这是真的,那么任何循环都会变成无限循环。@DavidRobinson从我嘴里说出了这些话。这很好地回答了这个问题。如果他的BASIC版本足够小(比如说,no-If,only-PRINT-and-GOTO等等),那么它就和他说的一模一样——如果一行被访问两次,它就是一个无限循环。因为这是一项作业,类似的情况也会发生。@RemcoGerlich如果是这样的话,问题应该相应地重新表述。他已经说过“我知道,如果任何一行被访问两次,那么它就会永远循环”,显然他的辅导助理不仅证实了这一点,而且给了他建议。所以我想我们可以把这句话当作是给定的——他需要检测一行是否被访问了两次。是的,除非我把访问过的
作为一个集合,如果我访问过
就写。它仍然是O(1)查找,但它使用的内存与访问的行数成比例,而不是程序中的行数。嗯,我认为程序最好遵循TA的提示。