Python:在不使用“setrecursionlimit”的情况下酸洗高度递归对象
当尝试 pickle 高度递归的树对象时,我收到了 RuntimeError: Maximum recursion Deleep Exeded
。就像这里的提问者一样。
他通过使用 sys.setrecursionlimit 设置更高的递归限制来解决他的问题。但我不想这样做:我认为这更像是一种解决方法,而不是解决方案。因为我希望能够对我的树进行 pickle,即使它们有 10,000 个节点。 (目前它在 200 左右失败。)
(此外,每个平台的真正递归限制都是不同的,我真的很想避免打开这个蠕虫罐。)
有什么方法可以从根本上解决这个问题吗?如果只有 pickle 模块使用循环而不是递归来 pickle,我就不会遇到这个问题。也许有人知道如何在不重写 pickle 模块的情况下导致类似的事情发生?
任何其他想法如何解决这个问题将不胜感激。
I've been getting RuntimeError: maximum recursion depth exceeded
when trying to pickle a highly-recursive tree object. Much like this asker here.
He solved his problem by setting the recursion limit higher with sys.setrecursionlimit
. But I don't want to do that: I think that's more of a workaround than a solution. Because I want to be able to pickle my trees even if they have 10,000 nodes in them. (It currently fails at around 200.)
(Also, every platform's true recursion limit is different, and I would really like to avoid opening this can of worms.)
Is there any way to solve this at the fundamental level? If only the pickle module would pickle using a loop instead of recursion, I wouldn't have had this problem. Maybe someone has an idea how I can cause something like this to happen, without rewriting the pickle module?
Any other idea how I can solve this problem will be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我想大多数人从未使用过如此深度的递归结构。由于最简单的序列化实现是递归的,因此您只会看到它们。
如果我是你,我不会在这里使用公开的递归数据结构。相反,我会对每个节点进行编号,并使用链接表来有效地将数字转换为具有该编号的节点。每个节点都将通过该表使用数字引用其他节点(例如其子节点)。一个简单的属性将使语法变得简单。除了这些属性之外,无需更改处理树遍历的代码。节点构造函数必须分配一个数字并将其自身放入链接表中,这也很简单。
链接表可能只是一个节点列表,其中列表中的索引用作节点号; Python 列表似乎可以通过索引进行有效访问。如果插入速度很重要,我会预先分配一个足够长的列表,其中填充 None;它不会占用太多空间。如果节点存储自己的编号,则该结构将可以在两个方向上廉价地遍历。
如您所见,对这样一棵树进行酸洗和反酸洗在任何深度都是微不足道的。
I suppose that most people never use recursive structures of such depth. Since easiest serialization implementations are recursive, you're going to only see them.
If I were you I'd not use an openly recursive data structure here. Instead I'd number every node and use a link table that efficiently translates a number to a node with that number. Every node would refer to other nodes (e.g. its children) via that table, using numbers. A simple property would make this syntactically easy. Beyond that properties, no code dealing with tree traversal would have to change. Node constructor will have to allocate a number and put itself into the link table, which is trivial, too.
The link table might be just a list of nodes, where index into the list serves as the node number; Python lists seem to have efficient access by index. If speed of inserts is important, I'd preallocate a long enough list filled with None; it would not take too much space. If nodes stored their own numbers, this structure would be cheaply traversable in both directions.
As you see, pickling and unpickling such a tree would be trivial at any depth.
为了使理解更容易,这里有一个完整的示例,只有一个链接来简化它:
另请注意,此结构可以轻松包含循环并且仍然可以简单地序列化。
To make understanding easier, here's a complete example, with only one link to simplify it:
Also note that this structure can easily contain cycles and still serialize plainly.
只是不要使用递归。
创建一个具有开放节点的堆栈(列表/队列)并对其进行处理。
像这样的东西(伪代码)
应该可以做到
Just dont use recursion.
Make a stack (list / queue) with open nodes and process this.
Something like this (pseudo code)
That should do it
我认为一个好的解决方案是梅内和 9000 的答案的结合。鉴于节点具有全局唯一的 ID(也许可以以某种方式使用内存地址),您可以执行此操作。诚然,这是一个草率的伪实现,但如果封装在树类中,通过一些抽象,它可能会非常简单。
I think a good solution is a combination of Mene's and 9000's answers. Given that nodes have globally unique IDs (maybe somehow memory addresses can be used as such) you can do this. Granted this is a sloppy pseudo-implementation, but with a bit of abstraction if encapsulated in a tree class it could be very simple.