簡體   English   中英

在單個項目上“迭代”的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

這行得通,但它似乎很浪費而且不是特別清晰。 在搜索 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM