简体   繁体   English

python中的RecursionError

[英]RecursionError in python

I am new in python and I graduated in mechanical engineering. 我是python的新手,我毕业于机械工程专业。 So I have no a lot of theoretical knowledge of computer science. 因此,我对计算机科学没有太多的理论知识。 I'm trying to develope a basic robot or rover whatever and I constantly want to check incoming datas from Arduino. 我正在尝试开发基本的机器人或漫游者,而我一直想检查来自Arduino的传入数据。 At first, Python program worked very nicely but after a while the program failed. 刚开始,Python程序运行得很好,但是一段时间后程序失败了。

I searched in google about "RecursionError: maximum recursion depth..." and any answer was not enough for me (sys.setrecursionlimit(10000), tail recursion function, detactors). 我在Google中搜索了“ RecursionError:最大递归深度...”,对我来说,任何答案都还不够(sys.setrecursionlimit(10000),尾递归函数,检测器)。

First question: 第一个问题:

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

oku()

when This codes was executed, the program is failing. 当执行此代码时,程序失败。

RecursionError: maximum recursion depth exceeded while pickling an object. RecursionError:腌制对象时超出了最大递归深度。

def oku():
    print("qwerty")

while True:
    oku()

There is no problem when I execute this code. 当我执行此代码时没有问题。 Why? 为什么?

Second question: 第二个问题:

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()

The program gives this error after running for a while. 程序运行一段时间后给出此错误。

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>

but when I changed call_read(self) like this: 但是当我像这样更改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)

I dont encounter any error. 我没有遇到任何错误。 Is this solution correct? 这个解决方案正确吗? Does the program generate a forward-looking error with while solution? 程序在使用while解决方案时是否会产生前瞻性错误?

here communicaiton class code.. 这里是通讯类代码。

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"

First Question 第一个问题

Python has a maximum recursion depth in order to prevent a stack overflow. Python具有最大的递归深度,以防止堆栈溢出。 This means that the call stack cannot exceed the maximum depth (1000 by default). 这意味着调用堆栈不能超过最大深度(默认为1000)。 So in your first example, the function oku calls itself many times, each time adding a call to the call stack. 因此,在第一个示例中,函数oku会多次调用自身,每次将调用添加到调用堆栈中。 Once oku calls itself 1000 times the maximum recursion depth is hit and Python raises a RecursionError . 一旦oku调用自身1000倍的最大递归深度,Python就会引发RecursionError

In your second example, oku may be called more than 1000 times, but each call is made after the previous call has completed execution. 在第二个示例中, oku可能被调用1000次以上,但是每个调用都是在上一个调用完成执行之后进行的。 So one call is added to the call stack, then removed, then another is added, and removed again, and so on. 因此,将一个调用添加到调用堆栈中,然后删除,然后再添加另一个,然后再次删除,依此类推。 In the first example, since the next call to oku happens inside the current call of oku , no calls are removed from the call stack. 在第一个例子,因为下一个呼叫oku的当前呼叫内发生的oku ,没有调用从调用堆栈中删除。

Second Question 第二个问题

The problem here and reason your second version works seem to be roughly the same as in your examples from the first question. 这里的问题和您的第二个版本工作的原因似乎与第一个问题中的示例大致相同。 The basic problem is that you call the same function recursively without any stopping conditions. 基本问题是,您在没有任何停止条件的情况下递归调用同一函数。 In this case, however you make the recursive call through timer_read.run() rather than directly. 但是,在这种情况下,您是通过timer_read.run()而不是直接进行递归调用的。

I believe the reason you get Fatal Python error: Cannot recover from stack overflow is because Python does not recognize this example as recursion since the recursion is happening through the threading Timer. 我相信您会收到Fatal Python error: Cannot recover from stack overflow的原因是,因为递归是通过线程计时器进行的,所以Python无法将此示例识别为递归。 Thus Python doesn't know to raise a RecursionError and the stack overflows. 因此,Python不知道引发RecursionError并且堆栈溢出。

Solution/Notes 解决方案/注意事项

It seems in these examples that there is no need use or benefit from using recursion at all. 在这些示例中,似乎完全没有必要使用递归或从中受益。 Recursion here is being used instead of a loop and a loop would be a better solution. 这里使用递归而不是循环,而循环将是更好的解决方案。 Especially since it seems like you want the process to repeat indefinitely. 特别是因为您似乎希望该过程无限期地重复。

When using recursion you need to make sure that you have a base case or stopping condition. 使用递归时,需要确保您具有基本情况或停止条件。 Essentially this is when your process is "done" (whatever that may mean for the application). 从本质上讲,这是您的流程“完成”的时间(无论对应用程序意味着什么)。 This will help prevent stack overflows (not a guarantee though). 这将有助于防止堆栈溢出(尽管不能保证)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM