python中的RecursionError

时间:2018-12-14 19:54:42

标签: python python-3.x

我是python的新手,我毕业于机械工程专业。因此,我对计算机科学没有太多的理论知识。我正在尝试开发基本的机器人或漫游者,而我一直想检查来自Arduino的传入数据。刚开始,Python程序工作得很好,但是一段时间后程序失败了。

我在Google中搜索了“ RecursionError:最大递归深度...”,对我来说,任何答案都还不够(sys.setrecursionlimit(10000),尾递归函数,检测器)。

第一个问题:

def oku():
    print("qwerty")
    oku()

oku()

执行此代码时,程序失败。

  

RecursionError:腌制对象时超出了最大递归深度。

def oku():
    print("qwerty")

while True:
    oku()

执行此代码没有问题。 为什么?

第二个问题:

from Arnocom import communication as COM
from threading import Timer
from Coordinates import location

class MainGUI(components):

def __init__(self, window):

    super().__init__(window)
    self.btn_ext.config(command=self.exit)
    self.btn_f.config(command=motions.foward)
    self.btn_s.config(command=motions.stop)
    # self.timer_flag = True

    lst = COM.main()
    for i in range(len(lst)):
        self.show_info(lst[i])


def show_info(self, info):
    self.lstbx_glnveri.insert(END, info)
    self.lstbx_glnveri.see(END)

def call_read(self):
        try:
            gln_veri = COM.read()
            print(gln_veri)
            if gln_veri is None:
                pass
            else:
                ow = location.analysis_data(gln_veri)
                self.show_info(ow)
        except Exception:
            pass
        timer_read.run()


root = Tk()

my_gui = MainGUI(root)

timer_read = Timer(0.01, my_gui.call_read)
timer_read.start()

root.mainloop()

程序运行一段时间后会出现此错误。

Fatal Python error: Cannot recover from stack overflow.

Current thread 0x000005c0 (most recent call first):
  File "C:\Users\evil\Desktop\_Project_GUI\venv\lib\site- 
  packages\serial\serialwin32.py", line 272 in read
  File "C:\Users\evil\Desktop\_Project_GUI\venv\lib\site- 
  packages\serial\serialutil.py", line 659 in read_until
  File "C:\Users\evil\Desktop\_Project_GUI\Arnocom.py", line 40 in read
  File "C:/Users/evil/Desktop/_Project_GUI/Form.py", line 38 in call_read
  File "C:\Users\evil\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 1158 in run
  File "C:/Users/evil/Desktop/_Project_GUI/Form.py", line 51 in call_read
 .
 same errors
 .
  File "C:\Users\evil\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 1158 in run
  File "C:/Users/evil/Desktop/_Project_GUI/Form.py", line 51 in call_read
 ...

Thread 0x00001648 (most recent call first):
  File "C:\Users\evil\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1283 in mainloop
  File "C:/Users/evil/Desktop/_Project_GUI/Form.py", line 77 in <module>

但是当我这样更改call_read(self)时:

self.timer_flag = True

def call_read(self):
    while self.timer_flag:
        try:
            gln_veri = COM.read()
            print(gln_veri)
            if gln_veri is None:
                pass
            else:
                ow = location.analysis_data(gln_veri)
                self.show_info(ow)
        except Exception:
            pass
        time.sleep(0.1)

我没有遇到任何错误。 此解决方案正确吗? 程序在使用while解决方案时是否会产生前瞻性错误?

这里是通信类代码。

import serial
import serial.tools.list_ports as port_list

class communication:

  @classmethod
  def main(cls):

    # store error message
    cls.msj_gndr = []
    cls.Arduino = serial.Serial()
    cls.Arduino.baudrate = 115200
    cls.Arduino.timeout = 0.01
    # collect error message
    cls.msj_gndr.append(cls.port_list())
    cls.msj_gndr.append(cls.open_port())
    cls.msj_gndr.append(cls.check_connection())
    return cls.msj_gndr

  @classmethod
  def read(cls):
    try:
        gelenveri = cls.Arduino.read_until(b';')
        if gelenveri != b'':
            return gelenveri
    except Exception:
        return "Connection Error"

1 个答案:

答案 0 :(得分:1)

第一个问题

Python具有最大的递归深度,以防止堆栈溢出。这意味着调用堆栈不能超过最大深度(默认为1000)。因此,在您的第一个示例中,函数oku会多次调用自身,每次将调用添加到调用堆栈中。一旦oku调用了1000次最大递归深度,Python便提出了RecursionError

在第二个示例中,oku可能被调用1000次以上,但是每个调用都是在上一个调用完成执行之后进行的。因此,将一个调用添加到调用堆栈中,然后删除,然后再添加另一个,然后再次删除,依此类推。在第一个示例中,由于对oku的下一次调用发生在当前oku的调用内,因此不会从调用堆栈中删除任何调用。

第二个问题

这里的问题和您的第二个版本起作用的原因似乎与第一个问题中的示例大致相同。基本问题是,您在没有任何停止条件的情况下递归调用同一函数。但是,在这种情况下,您是通过timer_read.run()而不是直接进行递归调用的。

我相信您得到Fatal Python error: Cannot recover from stack overflow的原因是因为Python不能通过递归Timer进行递归,因此无法将此示例识别为递归。因此,Python不知道引发RecursionError并且堆栈溢出。

解决方案/说明

在这些示例中,似乎完全没有必要使用递归或从中受益。这里使用递归而不是循环,而循环将是更好的解决方案。尤其是因为您似乎希望该过程无限期地重复。

使用递归时,需要确保您具有基本情况或停止条件。从本质上讲,这是您的流程“完成”的时间(无论对应用程序意味着什么)。这将有助于防止堆栈溢出(尽管不能保证)。