それをサポートする言語で複数の値を返すための標準的な方法は、しばしば混乱しています。
オプション:タプルの使用
次の簡単な例を考えてみます。
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0, y1, y2)
ただし、返される値の数が増えると、すぐに問題が発生します。4つまたは5つの値を返す場合はどうなりますか?もちろん、それらを繰り返し使用することはできますが、どの値がどこにあるのかを簡単に忘れてしまいます。また、受け取りたい場所をどこでも開梱するのは見苦しくなります。
オプション:辞書を使用する
次の論理的なステップは、ある種の「レコード表記」を導入することです。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:
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では、前の2つはおそらく配管の点で非常に似{ y0, y1, y2 }
ています-結局のところ、最終的__dict__
にはの内部のエントリになりますReturnValue
。
小さなオブジェクトである__slots__
属性には、Pythonによって提供される追加機能が1つあります。クラスは次のように表現できます。
class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
__slots__
宣言は、各変数の値を保持するために、各インスタンスにインスタンス変数と埋蔵量だけで十分なスペースのシーケンスを取り。は__dict__
インスタンスごとに作成されないため、スペースが節約されます。
オプション:使用するデータクラスを(パイソン3.7+)
Python 3.7の新しいデータクラスを使用して、自動的に追加された特別なメソッド、入力、その他の便利なツールを備えたクラスを返します。
@dataclass
class Returnvalue:
y0: int
y1: float
y3: int
def total_cost(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
オプション:リストを使用する
私が見逃していたもう1つの提案は、ビルザトカゲからのものです。
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
これは私の最も好きな方法ですが。私はHaskellへの暴露に汚染されていると思いますが、混合タイプのリストの考えは常に不快に感じてきました。この特定の例では、リストは混合タイプではありませんが、そうである可能性があります。
この方法で使用されるリストは、私が知る限り、タプルに関して実際には何も得ません。Pythonでのリストとタプルの唯一の本当の違いは、リストは変更可能であるのに対し、タプルは変更できないことです。
私は個人的に、関数型プログラミングの慣例を引き継ぐ傾向があります。同じタイプの要素をいくつでもリストに使用し、事前に定義されたタイプの要素をいくつでもタプルを使用します。
質問
長いプリアンブルの後に、避けられない質問が続きます。どちらの方法が良いと思いますか?
y3
していません。ローカル名を使用することもできます。これでも同じことができます。
y3
、y3がグローバルとして宣言されていない限り、これはNameError: global name 'y3' is not defined
おそらく単に3
?