fromiter
可以工作,但速度非常慢,因为它通过迭代器协议。将数据编码为 UTF-32(按系统字节顺序)并使用要快得多numpy.frombuffer https://docs.scipy.org/doc/numpy/reference/generated/numpy.frombuffer.html:
In [56]: x = ''.join(chr(random.randrange(0x0fff)) for i in range(1000))
In [57]: codec = 'utf-32-le' if sys.byteorder == 'little' else 'utf-32-be'
In [58]: %timeit numpy.frombuffer(bytearray(x, codec), dtype='U1')
2.79 µs ± 47 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [59]: %timeit numpy.fromiter(x, dtype='U1', count=len(x))
122 µs ± 3.82 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [60]: numpy.array_equal(numpy.fromiter(x, dtype='U1', count=len(x)), numpy.fr
...: ombuffer(bytearray(x, codec), dtype='U1'))
Out[60]: True
我用过sys.byteorder
判断是否编码utf-32-le
or utf-32-be
。另外,使用bytearray
代替encode
获取可变字节数组而不是不可变字节对象,因此生成的数组是可写的。
至于逆向转换,arr.view(dtype=f'U{arr.size}')[0]
有效,但使用item() https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.item.html速度更快一些,并生成一个普通的字符串对象,避免了可能出现的奇怪的边缘情况numpy.str_
不太像str
:
In [72]: a = numpy.frombuffer(bytearray(x, codec), dtype='U1')
In [73]: type(a.view(dtype=f'U{a.size}')[0])
Out[73]: numpy.str_
In [74]: type(a.view(dtype=f'U{a.size}').item())
Out[74]: str
In [75]: %timeit a.view(dtype=f'U{a.size}')[0]
3.63 µs ± 34 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [76]: %timeit a.view(dtype=f'U{a.size}').item()
2.14 µs ± 23.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
最后,请注意,NumPy 不像普通 Python 字符串对象那样处理空值。 NumPy 无法区分'asdf\x00\x00\x00'
and 'asdf'
,因此如果您的数据可能包含空代码点,则使用 NumPy 数组进行字符串操作是不安全的。