複数のアイテムを返すための規則はありますか?


10

特にPythonでは(これが一般化するかどうかはわかりません)、関数から複数のアイテムを返す「最良の」方法はありますか?

def func1():
    return a,b #equivalent to (a,b)

def func2():
    return[a,b]

def func3():
    return{"valueA":a,"valueB":b}

最初は私が最も一般的に見るものですが、最後のものがあなたが出力に名前を付けたのでより読みやすいコードを作成するように感じますが、私はこの方法によって作成されたある種のオーバーヘッドを見逃しているかもしれませんか?


複数の引数を再調整するわけではありません。これらすべての例では、たまたま複合データ型(それぞれタプル、リスト、および辞書)である単一の結果を返しています。どのデータ型を返すかは、関数とその使用方法によって異なります。
gardenhead

興味深いことに、私はそのように考えたことは一度もありません。あなたが答えを出せば、私はそれを受け入れることができます
デボン村岡

回答:


13

選択は発信者の観点から厳密に考慮される必要があると思います:消費者がする必要がある可能性が最も高いのは何ですか?

そして、各コレクションの顕著な特徴は何ですか?

  • タプルは順番にアクセスされ、不変です
  • リストは順番にアクセスされ、変更可能です
  • 辞書はキーでアクセスされます

リストとタプルはアクセスと同等ですが、リストは変更可能です。まあ、すぐに結果を解凍する場合は、呼び出し元には関係ありません。

score, top_player = play_round(players)
# or
idx, record = find_longest(records)

ここがリストなのかタプルなのかを気にする理由はここにはなく、タプルはどちらの側も単純です。

一方、返されたコレクションをそのまま保持し、コレクションとして使用する場合

points = calculate_vertices(shape)
points.append(another_point)
# Make a new shape

その後、リターンが変更可能であることは理にかなっています。均質性も重要な要素です。繰り返しパターンのシーケンスを検索する関数を記述したとします。返される情報は、パターンの最初のインスタンスのシーケンスのインデックス、繰り返しの数、およびパターン自体です。それらは同じ種類のものではありません。ピースをまとめてもかまいませんが、コレクションを変更する理由はありません。これはではありませんlist

今度は辞書です。

最後のコードは、出力に名前を付けているため、より読みやすいコードを作成します

はい。フィールドにキーを設定すると、異種混合データがより明確になりますが、ある程度の負担も伴います。繰り返しになりますが、「これから荷ほどきます」の場合、これは

round_results = play_round(players)
score, top_player = round_results["score"], round_results["top_player"]

(キーのリテラル文字列を避けても)、タプルバージョンと比較して不必要な作業です。

ここでの質問は3つあります。コレクションはどれほど複雑で、コレクションはどのくらいの期間保管されますか。また、同じ種類のコレクションをさまざまな場所で使用する必要がありますか?

メンバーが3つ以上ある場合、特にネストがある場合は、キー付きアクセスの戻り値がタプルよりも意味をなすようになることをお勧めします。

shape["transform"]["raw_matrix"][0, 1] 
# vs.
shape[2][4][0, 1]

それは次の質問につながります:コレクションはこのスコープをそのままにして、それを作成した呼び出しから離れた場所にいますか?あちこちに鍵付きのアクセスがあれば、理解しやすくなります。

3番目の質問-再利用-は、提示しなかった4番目のオプションとして単純なカスタムデータ型を指しています。

構造は、この1つの機能によってのみ所有されますか?または、多くの場所で同じ辞書レイアウトを作成していますか?プログラムの他の多くの部分がこの構造で動作する必要がありますか?繰り返される辞書のレイアウトは、クラスに分解する必要があります。おまけとして、ビヘイビアを付けることができます。おそらく、データを操作する関数の一部がメソッドとしてカプセル化されます。

5番目の優れた軽量オプションはnamedtuple()です。これは、本質的に、不変の形式のディクショナリ戻り値です。


ユーザー定義クラスのインスタンスについてまったく言及しない理由はありますか?これは、あらゆるOO言語のgotoソリューションになるはずです。
Esben Skov Pedersen

1
これは、最後から3番目と最後から2番目の段落@EsbenSkovPedersenで説明されています。「ディクショナリーの繰り返しレイアウトは、クラスに分解する必要があります。
jscs

1

複数の引数を返す関数について考えないでください。概念的には、関数は単一の引数を受け取ることと返すことの両方と考えるのが最善です。複数の引数を受け入れるように見える関数は、実際にはタプル(以前の製品)タイプの単一の引数のみを受け取ります。同様に、複数の引数を返す関数は、単純にタプルを返します。

Pythonの場合:

def func(a, b, c):
  return b, c

次のように書き直すことができます

def func(my_triple):
  return (my_triple[1], my_triple[2])

比較を明確にするため。

最初のケースは、後者の単なる構文糖です。どちらも引数としてトリプルを受け取りますが、最初の引数はパターンに一致して、構成要素への自動分解を実行します。したがって、完全な一般的なパターンマッチングのない言語でも、一部のタイプで何らかの基本的なパターンマッチングを許可します(Pythonでは、製品タイプとレコードタイプの両方でパターンマッチングを許可しています)。


手元の質問に戻ると、「任意の関数の戻り値の型は何か」と尋ねるようなものなので、質問に対する答えは1つではありません。それは機能とユースケースに依存します。そして偶然にも、「複数の戻り値」が本当に独立している場合、それらはおそらく別々の関数によって計算されるべきです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.