"iterating" 对单个项目的 pythonic 方式是什么?
What is the pythonic way of "iterating" over a single item?
我经常遇到这个问题,如果没有一些非常简单和 pythonic 的单行解决方案,我会感到惊讶。
假设我有一个方法或函数将列表或其他一些可迭代对象作为参数。我希望对对象中的每个项目执行一次操作。
有时,只有一个项目(例如,一个浮点值)被传递给这个函数。在这种情况下,我的 for 循环不知道该怎么办。因此,我发现自己在代码中添加了以下代码片段:
from collections.abc import Sequence
def my_function(value):
if not isinstance(value, Sequence):
value = [value]
# rest of my function
这行得通,但看起来很浪费,而且不是特别清晰。在搜索 Whosebug 时,我还发现字符串被视为序列,因此如果参数错误,这段代码很容易中断。感觉这不是正确的方法。
我有 MATLAB 背景,这在该语言中得到了巧妙的解决,因为标量被视为 1x1 矩阵。我希望,至少,有一个内置的东西,比如 numpy 的 atleast_1d function,如果它不是一个,它会自动将任何东西转换成一个可迭代的东西。
简短的回答是不,没有简单的built-in。是的,如果你想让 str
(或 bytes
或 bytes-like 之类的东西)充当标量值,它会变得更丑陋。 Python 期望调用者遵守接口约定;如果你说你接受序列,那么就这么说吧,它由调用者来包装任何单独的参数。
如果您必须这样做,有两种显而易见的方法:
首先是让您的函数接受可变参数而不是单个参数,并将其留给调用者解压任何序列,这样您就可以始终迭代接收到的可变参数:
def my_function(*values):
for val in values:
# Rest of function
带有单个项目的来电者用 my_function(a, b)
呼叫您,带有序列的呼叫者用 my_function(*seq)
呼叫您。后者确实会产生一些开销以将序列解压缩为新的 tuple
以供 my_function
接收,但在许多情况下这很好。
如果出于某种原因这不可接受,另一种解决方案是按照您关心的任何规则推出您自己的“确保可迭代”转换器函数:
from collections.abc import ByteString
def ensure_iterable(obj):
if isinstance(obj, (str, ByteString)):
return (obj,) # Treat strings and bytes-like stuff as scalars and wrap
try:
iter(obj) # Simplest way to test if something is iterable is to try to make it an iterator
except TypeError:
return (obj,) # Not iterable, wrap
else:
return obj # Already iterable
my_function
可用于:
def my_function(value):
value = ensure_iterable(value)
我会鸭式:
def first(item):
try:
it=iter(item)
except TypeError:
it=iter([item])
return next(it)
测试一下:
tests=[[1,2,3],'abc',1,1.23]
for e in tests:
print(e, first(e))
打印:
[1, 2, 3] 1
abc a
1 1
1.23 1.23
Python 是一种通用语言,具有真正的标量,以及像列表这样的可迭代对象。
MATLAB 没有真正的标量。基础对象是一个二维矩阵。它最初并不是一种通用语言。
numpy
将类似 MATLAB 的数组添加到 Python,但它也可以有 0d 数组 (scalar arrays
),这可能会让任性的 MATLAB 用户头疼。
许多 numpy
函数都有将其输入转换为数组的规定。这样他们就可以处理列表输入以及数组
In [10]: x = np.array(3)
In [11]: x
Out[11]: array(3)
In [12]: x.shape
Out[12]: ()
In [13]: for i in x: print(x)
Traceback (most recent call last):
Input In [13] in <cell line: 1>
for i in x: print(x)
TypeError: iteration over a 0-d array
它还有确保数组为 1d 或 2 ...
的实用函数
In [14]: x = np.atleast_1d(1)
In [15]: x
Out[15]: array([1])
In [16]: for i in x: print(i)
1
但是像 old-fashion MATLAB 一样,我们更愿意避免在 numpy
中进行迭代。它没有 jit
编译功能,无法让当前的 MATLAB 用户进行迭代。技术上 numpy
函数确实使用迭代,但它通常在编译代码中。
np.sin
应用于各种输入:
In [17]: np.sin(1) # scalar
Out[17]: 0.8414709848078965
In [18]: np.sin([1,2,3]) # list
Out[18]: array([0.84147098, 0.90929743, 0.14112001])
In [19]: np.sin(np.array([1,2,3]).reshape(3,1))
Out[19]:
array([[0.84147098],
[0.90929743],
[0.14112001]])
从技术上讲,[17] 结果是 numpy scalar
,而不是基数 python 浮点数:
In [20]: type(Out[17])
Out[20]: numpy.float64
我经常遇到这个问题,如果没有一些非常简单和 pythonic 的单行解决方案,我会感到惊讶。
假设我有一个方法或函数将列表或其他一些可迭代对象作为参数。我希望对对象中的每个项目执行一次操作。
有时,只有一个项目(例如,一个浮点值)被传递给这个函数。在这种情况下,我的 for 循环不知道该怎么办。因此,我发现自己在代码中添加了以下代码片段:
from collections.abc import Sequence
def my_function(value):
if not isinstance(value, Sequence):
value = [value]
# rest of my function
这行得通,但看起来很浪费,而且不是特别清晰。在搜索 Whosebug 时,我还发现字符串被视为序列,因此如果参数错误,这段代码很容易中断。感觉这不是正确的方法。
我有 MATLAB 背景,这在该语言中得到了巧妙的解决,因为标量被视为 1x1 矩阵。我希望,至少,有一个内置的东西,比如 numpy 的 atleast_1d function,如果它不是一个,它会自动将任何东西转换成一个可迭代的东西。
简短的回答是不,没有简单的built-in。是的,如果你想让 str
(或 bytes
或 bytes-like 之类的东西)充当标量值,它会变得更丑陋。 Python 期望调用者遵守接口约定;如果你说你接受序列,那么就这么说吧,它由调用者来包装任何单独的参数。
如果您必须这样做,有两种显而易见的方法:
首先是让您的函数接受可变参数而不是单个参数,并将其留给调用者解压任何序列,这样您就可以始终迭代接收到的可变参数:
def my_function(*values):
for val in values:
# Rest of function
带有单个项目的来电者用 my_function(a, b)
呼叫您,带有序列的呼叫者用 my_function(*seq)
呼叫您。后者确实会产生一些开销以将序列解压缩为新的 tuple
以供 my_function
接收,但在许多情况下这很好。
如果出于某种原因这不可接受,另一种解决方案是按照您关心的任何规则推出您自己的“确保可迭代”转换器函数:
from collections.abc import ByteString
def ensure_iterable(obj):
if isinstance(obj, (str, ByteString)):
return (obj,) # Treat strings and bytes-like stuff as scalars and wrap
try:
iter(obj) # Simplest way to test if something is iterable is to try to make it an iterator
except TypeError:
return (obj,) # Not iterable, wrap
else:
return obj # Already iterable
my_function
可用于:
def my_function(value):
value = ensure_iterable(value)
我会鸭式:
def first(item):
try:
it=iter(item)
except TypeError:
it=iter([item])
return next(it)
测试一下:
tests=[[1,2,3],'abc',1,1.23]
for e in tests:
print(e, first(e))
打印:
[1, 2, 3] 1
abc a
1 1
1.23 1.23
Python 是一种通用语言,具有真正的标量,以及像列表这样的可迭代对象。
MATLAB 没有真正的标量。基础对象是一个二维矩阵。它最初并不是一种通用语言。
numpy
将类似 MATLAB 的数组添加到 Python,但它也可以有 0d 数组 (scalar arrays
),这可能会让任性的 MATLAB 用户头疼。
许多 numpy
函数都有将其输入转换为数组的规定。这样他们就可以处理列表输入以及数组
In [10]: x = np.array(3)
In [11]: x
Out[11]: array(3)
In [12]: x.shape
Out[12]: ()
In [13]: for i in x: print(x)
Traceback (most recent call last):
Input In [13] in <cell line: 1>
for i in x: print(x)
TypeError: iteration over a 0-d array
它还有确保数组为 1d 或 2 ...
的实用函数In [14]: x = np.atleast_1d(1)
In [15]: x
Out[15]: array([1])
In [16]: for i in x: print(i)
1
但是像 old-fashion MATLAB 一样,我们更愿意避免在 numpy
中进行迭代。它没有 jit
编译功能,无法让当前的 MATLAB 用户进行迭代。技术上 numpy
函数确实使用迭代,但它通常在编译代码中。
np.sin
应用于各种输入:
In [17]: np.sin(1) # scalar
Out[17]: 0.8414709848078965
In [18]: np.sin([1,2,3]) # list
Out[18]: array([0.84147098, 0.90929743, 0.14112001])
In [19]: np.sin(np.array([1,2,3]).reshape(3,1))
Out[19]:
array([[0.84147098],
[0.90929743],
[0.14112001]])
从技术上讲,[17] 结果是 numpy scalar
,而不是基数 python 浮点数:
In [20]: type(Out[17])
Out[20]: numpy.float64