gpt4 book ai didi

python - 为什么在 numpy.genfromtxt() 中使用间接定义的转换器会失败并出现错误 "RecursionError: maximum recursion depth exceeded"?

转载 作者:行者123 更新时间:2023-12-01 07:46:35 24 4
gpt4 key购买 nike

我猜这个问题只适合那些喜欢挖掘 Python Tracebacks 源代码的挑战的人……但也许有人立刻就知道答案。

这应该很容易重现,请参阅下面的代码(我想根据您的硬件和 sys.setrecursionlimit() 的值,您可能需要从我的值 2000 增加最大迭代次数)。

它是 numpy.genfromtxt 读取由单个字符 0 组成的 1 列 1 行 CSV 文件。当显式设置“转换器”(在下面注释掉)时,一切都很好而且很快。当“converters”如代码中所示间接设置时,Python 正在执行一些完全不必要的递归操作,并且代码在 1400 到 1500 次迭代之间失败(在我的计算机上),并出现错误“RecursionError:超出最大递归深度”。在代码失败之前,随着迭代(大概还有递归深度)的增加,它会变得越来越慢。 Traceback指向所涉及的源代码,但我不知道如何深入研究它。

问题是:为什么这段代码不能与显式设置“转换器”的代码完全一样?这是一个错误,还是有意义;也就是说,我的代码很糟糕?

#Spyder 3.3.3 | Python 3.7.3 64-bit | Qt 5.9.6 | PyQt5 5.9.2 | Windows 10 

import numpy as np

the_converters = {'data': lambda s : 0}

jcount = 0
while jcount < 2000:

jcount = jcount + 1
print(jcount)

the_array = np.genfromtxt('recursion_debug.csv', delimiter =',', \
names = 'data', \
converters = the_converters, \
#converters = {'data': lambda s : 0}, \
)

最佳答案

In [1]: txt="""0,0 
...: 0,0"""
In [14]: cvt = {'data':lambda s: 10}
In [15]: cvt
Out[15]: {'data': <function __main__.<lambda>(s)>}
In [16]: np.genfromtxt(txt.splitlines(),delimiter=',',usecols=[0],names='data',converters=cvt)
Out[16]: array([10, 10])
In [17]: cvt
Out[17]:
{'data': <function __main__.<lambda>(s)>,
0: functools.partial(<function genfromtxt.<locals>.tobytes_first at 0x7f5e71154bf8>, conv=<function <lambda> at 0x7f5e70928b70>)}

genfromtxt 正在修改 cvt 对象(就地),并且此效果是累积的:

In [18]: np.genfromtxt(txt.splitlines(),delimiter=',',usecols=[0],names='data',converters=cvt)                           
Out[18]: array([10, 10])
In [19]: cvt
Out[19]:
{'data': <function __main__.<lambda>(s)>,
0: functools.partial(<function genfromtxt.<locals>.tobytes_first at 0x7f5e82ea4bf8>, conv=functools.partial(<function genfromtxt.<locals>.tobytes_first at 0x7f5e71154bf8>, conv=<function <lambda> at 0x7f5e70928b70>))}

请注意,命名的键值不会改变;相反,它添加了一个带有修改后的转换器的列号键。

如果我们内联创建字典,并且只提供 lambda(或函数),则该函数不会被修改:

In [26]: cvt = lambda s: 10                                                                                              
In [27]: np.genfromtxt(txt.splitlines(),delimiter=',',usecols=[0],names='data',converters={'data':cvt})
Out[27]: array([10, 10])
In [28]: cvt
Out[28]: <function __main__.<lambda>(s)>

现在创建一个也显示输入字符串的函数:

In [53]: def foo(s): 
...: print(s)
...: return '10'
...:
In [54]: cvt = {'data':foo}

如果我指定编码,字典仍然会被修改(新键),但函数不会被修改:

In [55]: np.genfromtxt(txt.splitlines(),delimiter=',',usecols=[0],names='data',converters=cvt, encoding=None)            
0
0
0
Out[55]: array(['10', '10'], dtype='<U2')
In [56]: cvt
Out[56]: {'data': <function __main__.foo(s)>, 0: <function __main__.foo(s)>}

如果没有编码(或默认的“字节”),则会添加 tobytes 包装器,并将字节字符串传递给我的函数:

In [57]: np.genfromtxt(txt.splitlines(),delimiter=',',usecols=[0],names='data',converters=cvt)                           
b'0'
b'0'
b'0'
b'0'
Out[57]: array(['10', '10'], dtype='<U2')
In [58]: cvt
Out[58]:
{'data': <function __main__.foo(s)>,
0: functools.partial(<function genfromtxt.<locals>.tobytes_first at 0x7f5e82e9c730>, conv=<function foo at 0x7f5e7113e268>)}

===

添加 functools.partial 的代码是旧 Py2 到 Py3 字节到 unicode 开关的一部分:

   elif byte_converters:
# converters may use decode to workaround numpy's old behaviour,
# so encode the string again before passing to the user converter
def tobytes_first(x, conv):
if type(x) is bytes:
return conv(x)
return conv(x.encode("latin1"))
import functools
user_conv = functools.partial(tobytes_first, conv=conv)
else:
user_conv = conv

关于python - 为什么在 numpy.genfromtxt() 中使用间接定义的转换器会失败并出现错误 "RecursionError: maximum recursion depth exceeded"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56432770/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com