複数の値を返す標準的な方法は、多くの場合、それをサポートする言語ではタプリング。
オプション: タプルを使用する
次の些細な例を考えてみましょう。
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
ただし、小さなオブジェクトに対しては、Python によって属性という追加機能が提供されます__slots__
。クラスは次のように表現できます。
class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
宣言
__slots__
はインスタンス変数のシーケンスを受け取り、各インスタンスに各変数の値を保持するのに十分なスペースを予約します。__dict__
インスタンスごとには作成されないため、スペースが節約されます。
オプション:データクラス(Python 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)
オプション: リストを使用する
私が見落としていたもう一つの提案は、Bill the Lizard からのものです。
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
ただし、これは私が最も嫌いな方法です。Haskell に触れたことで汚れているのかもしれませんが、混合型リストという考え方は、私にとって常に不快に感じられてきました。この特定の例では、リストは混合型ではありませんが、混合型である可能性は考えられます。
このように使用されるリストは、私が知る限り、タプルと比べて何も得るものはありません。Pythonにおけるリストとタプルの唯一の違いは、リストは可変一方、タプルはそうではありません。
私は個人的に、関数型プログラミングの規則を引き継ぐ傾向があります。つまり、同じ型の任意の数の要素にはリストを使用し、事前に決定された型の固定数の要素にはタプルを使用します。
質問
長い前置きが終わったら、避けられない質問が来ます。どの方法が最良だと思いますか?
ベストアンサー1
名前付きタプル2.6ではこの目的のために追加されました。os.stat同様の組み込み例については、こちらをご覧ください。
>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2
Python 3の最近のバージョン(3.6以降だと思います)では、新しいtyping
ライブラリはNamedTuple
クラスを使用すると、名前付きタプルの作成がより簡単かつ強力になります。 を継承すると、typing.NamedTuple
ドキュメント文字列、デフォルト値、型注釈を使用できるようになります。
例 (ドキュメントより):
class Employee(NamedTuple): # inherit from typing.NamedTuple
name: str
id: int = 3 # default value
employee = Employee('Guido')
assert employee.id == 3