[英]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
這行得通,但它似乎很浪費而且不是特別清晰。 在搜索 StackOverflow 時,我還發現字符串被認為是序列,因此如果參數錯誤,這段代碼很容易中斷。 只是感覺不是正確的方法。
我來自 MATLAB 背景,由於標量被視為 1x1 矩陣,因此可以用該語言巧妙地解決這個問題。 至少,我希望有一個內置的東西,比如 numpy 的atleast_1d 函數,如果它不是一個,它會自動將任何東西轉換為可迭代的。
簡短的回答是不,沒有簡單的內置。 是的,如果您希望str
(或bytes
或類似字節的東西或其他)充當標量值,它會變得更丑陋。 Python 期望調用者遵守接口契約; 如果你說你接受序列,就這么說吧,它由調用者來包裝任何單獨的參數。
如果你必須這樣做,有兩種明顯的方法可以做到:
首先是讓您的函數接受可變參數而不是單個參數,並將其留給調用者解壓縮任何序列,因此您始終可以迭代收到的可變參數:
def my_function(*values):
for val in values:
# Rest of function
具有單個項目的調用者使用my_function(a, b)
調用您,具有序列的調用者使用my_function(*seq)
調用您。 后者確實會產生一些開銷來將序列解包到my_function
接收的新元tuple
,但在許多情況下這很好。
如果由於某種原因這不可接受,另一種解決方案是推出自己的“確保可迭代”轉換器功能,遵循您關心的任何規則:
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)
Python 是一種通用語言,具有真正的標量以及列表等可迭代對象。
MATLAB 沒有真正的標量。 基礎對象是一個二維矩陣。 它並不是作為一種通用語言開始的。
numpy
在 Python 中添加了類似 MATLAB 的數組,但它也可以有 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
但就像老式 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
我會鴨式:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.