【问题标题】:RecursionError in pythonpython中的递归错误
【发布时间】:2018-12-14 19:54:41
【问题描述】:

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

我在 google 中搜索了“RecursionError: maximum recursion depth...”,但任何答案对我来说都是不够的(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"

【问题讨论】:

  • 尝试阅读How to Ask
  • 第一个你只是用 while True 循环无穷大
  • 我很喜欢你的第一个问题。这两个oku() 函数根本不同,这个概念被称为recursion vs iterationanother link,并且,恰如其分地,未经检查的递归会导致递归错误,因为......堆栈溢出。所以,欢迎堆栈溢出!坦率地说,您的第二个问题太长而无法检查,您可能希望将其缩小到相关部分。但我怀疑它与递归与迭代有关。
  • StackOverflow 的问答风格在您将每篇文章限制为一个问题时效果最佳。不过,没有什么能阻止你发表几个不同的帖子,每个帖子都有不同的问题。

标签: python python-3.x


【解决方案1】:

第一个问题

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

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

第二个问题

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

我相信您得到Fatal Python error: Cannot recover from stack overflow 的原因是因为Python 不将此示例识别为递归,因为递归是通过线程定时器发生的。因此 Python 不知道引发 RecursionError 并且堆栈溢出。

解决方案/注意事项

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

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

【讨论】:

  • 感谢您的回答。你已经非常清楚地解释了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-28
  • 2012-11-19
相关资源
最近更新 更多