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>))}
Обратите внимание, что значение поименованного ключа не изменяется;скорее он добавляет ключ номера столбца с измененным конвертером.
Если вместо этого мы создаем словарь in-line и просто предоставляем лямбду (или функцию), функция не изменяется:
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}
Если я укажу encoding
, словарь все еще изменяется (новый ключ), но функция не изменяется:
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