Python関数から複数の値を返すための代替手段 [closed] 質問する

Python関数から複数の値を返すための代替手段 [closed] 質問する

複数の値を返す標準的な方法は、多くの場合、それをサポートする言語ではタプリング

オプション: タプルを使用する

次の些細な例を考えてみましょう。

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

からPython リファレンスマニュアル:

宣言__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

おすすめ記事