“迭代”单个项目的 Python 方式是什么?

Drp*_*ton 5 python numpy

我经常遇到这个问题,如果没有一些非常简单且Python式的单行解决方案,我会感到惊讶。

假设我有一个方法或函数,它将列表或其他可迭代对象作为参数。我希望对对象中的每个项目执行一次操作。

有时,仅将单个项目(例如浮点值)传递给此函数。在这种情况下,我的 for 循环不知道该怎么办。因此,我发现自己在代码中添加了以下代码片段:

from collections.abc import Sequence

def my_function(value):
   if not isinstance(value, Sequence):
      value = [value]

   # rest of my function
Run Code Online (Sandbox Code Playgroud)

这可行,但看起来很浪费而且不是特别清晰。在搜索 StackOverflow 时,我还发现字符串被视为序列,因此如果参数错误,这段代码很容易中断。这感觉不是正确的方法。

我有 MATLAB 背景,这个问题在该语言中得到了很好的解决,因为标量被视为 1x1 矩阵。我希望至少有一个内置的,类似于 numpy 的atleast_1d function 的东西,它会自动将任何东西转换为可迭代的(如果它不是可迭代的)。

Sha*_*ger 3

简短的回答是否定的,没有简单的内置功能。是的,如果你想要str(或bytes类似字节的东西或其他什么)充当标量值,它会变得更丑陋。Python 希望调用者遵守接口契约;如果您说您接受序列,请这么说,并且由调用者来包装任何单独的参数。

如果您必须这样做,有两种明显的方法可以做到:

首先是让您的函数接受可变参数而不是单个参数,并将其留给调用者来解压任何序列,以便您始终可以迭代收到的可变参数:

def my_function(*values):
    for val in values:
        # Rest of function
Run Code Online (Sandbox Code Playgroud)

具有单个项目的呼叫者会呼叫您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
Run Code Online (Sandbox Code Playgroud)

my_function可以与:

def my_function(value):
   value = ensure_iterable(value)
Run Code Online (Sandbox Code Playgroud)