xlim - python histogram




你如何在Python中返回多個值? (9)

在支持它的語言中返回多個值的規範方式通常很tupling

選項:使用元組

考慮這個微不足道的例子:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0,y1,y2)

但是,隨著返回值的數量增加,這很快就會出現問題。 如果你想返回四個或五個值呢? 當然,你可以繼續把它們弄髒,但很容易忘記哪個值是在哪裡。 將它們解包到任何你想接收它們的地方也是相當難看的。

選項:使用字典

下一個合乎邏輯的步驟似乎是引入某種“記錄符號”。 在Python中,執行此操作的顯而易見的方法是通過dict

考慮以下:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

(編輯 - 為了清楚起見,y0,y1和y2只是抽象的標識符,正如指出的那樣,在實踐中你會使用有意義的標識符)

現在,我們有了一個機制,可以將返回對象的特定成員投影出來。 例如,

result['y0']

選項:使用一個類

但是,還有另一種選擇。 我們可以返回一個專門的結構。 我已經在Python的上下文中構建了這個框架,但我相信它也適用於其他語言。 事實上,如果你在C工作,這可能是你唯一的選擇。 開始:

class ReturnValue(object):
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return ReturnValue(y0, y1, y2)

在Python中,前兩者在管道方面可能非常相似 - 畢竟{ y0, y1, y2 }最終只能作為ReturnValue的內部__dict__中的條目。

Python為小對象提供了另一個特性,即__slots__屬性。 這個班可以表達為:

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

Python參考手冊

__slots__聲明採用一系列實例變量,並在每個實例中保留足夠的空間以保存每個變量的值。 空間被保存,因為__dict__不是為每個實例創建的。

選項:使用列表

我忽略的另一個建議來自比爾蜥蜴:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

儘管這是我最不喜歡的方法。 我想我已經接觸到Haskell,但混合類列表的想法一直讓我感到不舒服。 在這個特定的例子中,列表是非混合類型,但它可能是可以的。 據我所知,以這種方式使用的列表實際上並沒有獲得關於元組的任何信息。 Python中的列表和元組之間唯一真正的區別是列表是mutable ,而元組則不是。 我個人傾向於繼承函數式編程的約定:使用相同類型的任意數量的元素的列表,以及用於固定數量的預定類型的元素的元組。

在長篇序言之後,出現不可避免的問題。 哪種方法(你認為)最好?

我通常會發現自己要去字典路線,因為它涉及的設置工作較少。 然而,從類型的角度來看,您最好走上課程路線,因為這可能會幫助您避免混淆字典所代表的內容。 另一方面,Python社區中有一些人認為隱式接口應該比顯式接口更受歡迎 ,此時對象的類型實際上並不相關,因為您基本上依賴於約定,即相同的屬性將始終具有相同的含義。

那麼,如何在Python中返回多個值?


Python的元組,字典和對象為程序員提供了小數據結構(“事物”)的正式性和便利性之間的平衡權衡。 對我而言,如何表現事物的選擇主要取決於我將如何使用該結構。 在C ++中,儘管可以合法地將方法放在struct上,但對於使用方法的對象而言,使用struct來處理純數據項和class是一種常見慣例; 我的習慣在Python中類似,用dicttuple代替struct

對於坐標集,我將使用一個tuple而不是一個點classdict (並且請注意,您可以使用tuple作為字典關鍵字,因此dict可以創建稀疏的多維數組)。

如果我要迭代一系列事物,我更喜歡在迭代中解開tuple s:

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

...因為對象版本更加混亂:

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

...更不用說dict

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

如果這個東西被廣泛使用,並且你發現自己在代碼中的多個地方對它進行類似的非平凡操作,那麼通常有必要用適當的方法將它變成一個類對象。

最後,如果我要與非Python系統組件交換數據,我經常會將它們保留為dict因為它最適合JSON序列化。


S.Lott提出的命名容器類的建議+1。

對於python 2.6或更高版本, 命名元組提供了一種輕鬆創建這些容器類的有用方法,並且結果是“輕量級且不需要比常規元組更多的內存”。


另一種選擇是使用發電機:

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4


>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

雖然恕我直言元組通常是最好的,除非返回的值是封裝在類中的候選者。


在像Python這樣的語言中,我通常會使用字典,因為它比創建新類的開銷少。

但是,如果我發現自己經常返回相同的一組變量,那麼這可能涉及到一個我會分解出來的新班級。


很多答案建議您需要返回某種類型的集合,如字典或列表。 你可以不用額外的語法,只需寫出返回值,用逗號分隔。 注意:這在技術上返回一個元組。

def f():
    return True, False
x, y = f()
print(x)
print(y)

得到:

True
False

我投票給字典。

我發現如果我創建一個返回超過2-3個變量的函數,我會將它們折疊成一個字典。 否則,我傾向於忘記我返回的順序和內容。

此外,引入“特殊”結構會使您的代碼更難以遵循。 (其他人將不得不搜索代碼來找出它是什麼)

如果您關心類型查詢,請使用描述性字典鍵,例如'x-values list'。

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

我會用一個字典來傳遞和返回一個函數的值:

使用表單中定義的變量form

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}


def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

這是我和處理單元最有效的方式。

你只需要傳入一個指針並返回一個指針。

無論何時在代碼中進行更改,都無需更改函數(其中有數千個參數)。


每當元組感覺“自然”時,我更喜歡使用元組; 坐標是一個典型的例子,其中獨立的對象可以獨立存在,例如單軸縮放計算。

僅當分組對像不總是相同時,我才使用字典作為返回值。 想想可選的電子郵件標題

對於其他情況,組合對像在組內具有固有含義或需要具有自己方法的完全對象時,我使用一個類。


>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3




return-value