我经常遇到这个问题,如果没有一些非常简单且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 的东西,它会自动将任何东西转换为可迭代的(如果它不是可迭代的)。
简短的回答是否定的,没有简单的内置功能。是的,如果你想要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)
| 归档时间: |
|
| 查看次数: |
223 次 |
| 最近记录: |