web-dev-qa-db-ja.com

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

Python具体的に(これが一般化するかどうかはわかりません)では、関数から複数の項目を返す「最良の」方法はありますか?

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

def func2():
    return[a,b]

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

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

9
Devon Muraoka

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

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

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

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

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

ここがリストなのかタプルなのかを気にする必要はありません。タプルはどちらの側も単純です。

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

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

その場合、リターンが変更可能であることは理にかなっています。均質性もここで重要な要素です。繰り返しパターンのシーケンスを検索する関数を記述したとします。返される情報は、パターンの最初のインスタンスのシーケンスのインデックス、繰り返し数、およびパターン自体です。それらは同じ種類のものではありません。ピースをまとめてもかまいませんが、collectionを変更する理由はありません。これは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() です。これは本質的に、不変の形式のディクショナリ戻り値です。

12
jscs

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

Pythonの場合:

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

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

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

比較を明確にするため。

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


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

1
gardenhead