85

Python では、関数が複数の値を返すようにすることができます。これは不自然な例です:

def divide(x, y):
    quotient = x/y
    remainder = x % y
    return quotient, remainder  

(q, r) = divide(22, 7)

これは非常に便利なようですが、悪用される可能性もあるようです (「関数 X は、必要なものを中間値として既に計算しています。X にその値も返させましょう」)。

いつ線を引いて別のメソッドを定義する必要がありますか?

4

9 に答える 9

111

絶対に(あなたが提供した例のために)。

タプルは Python の第一級市民です

divmod()まさにそれを行う組み込み関数があります。

q, r = divmod(x, y) # ((x - x%y)/y, x%y) Invariant: div*y + mod == x

他にも例があります: zipenumeratedict.items

for i, e in enumerate([1, 3, 3]):
    print "index=%d, element=%s" % (i, e)

# reverse keys and values in a dictionary
d = dict((v, k) for k, v in adict.items()) # or 
d = dict(zip(adict.values(), adict.keys()))

ところで、ほとんどの場合、括弧は必要ありません。Python ライブラリ リファレンスからの引用:

タプルは、さまざまな方法で構築できます。

  • 括弧のペアを使用して空のタプルを示します: ()
  • シングルトン タプルの末尾のコンマの使用: a, または (a,)
  • 項目をコンマで区切る: a、b、c または (a、b、c)
  • tuple() ビルトインの使用: tuple() または tuple(iterable)

関数は単一の目的を果たす必要があります

したがって、単一のオブジェクトを返す必要があります。あなたの場合、このオブジェクトはタプルです。タプルをアドホックな複合データ構造と考えてください。ほとんどすべての単一関数が複数の値を返す言語があります (Lisp のリスト)。

(x, y)の代わりにreturn で十分な場合もありPoint(x, y)ます。

名前付きタプル

Python 2.6 での名前付きタプルの導入により、多くの場合、単純なタプルではなく名前付きタプルを返すことが推奨されます。

>>> import collections
>>> Point = collections.namedtuple('Point', 'x y')
>>> x, y = Point(0, 1)
>>> p = Point(x, y)
>>> x, y, p
(0, 1, Point(x=0, y=1))
>>> p.x, p.y, p[0], p[1]
(0, 1, 0, 1)
>>> for i in p:
...   print(i)
...
0
1
于 2008-09-14T20:54:14.190 に答える
27

まず、Python では次のことが許可されていることに注意してください (括弧は必要ありません)。

q, r = divide(22, 7)

あなたの質問に関しては、どちらにしても厳格なルールはありません。単純な (そして通常は不自然な) 例では、特定の関数が単一の目的を持ち、結果として単一の値になることが常に可能であるように見えるかもしれません。ただし、実際のアプリケーションに Python を使用すると、複数の値を返す必要がある多くのケースにすぐに遭遇し、よりクリーンなコードになります。

ですから、理にかなっていることは何でもしてください。人為的な慣習に準拠しようとしないでください。Python は複数の戻り値をサポートしているため、必要に応じて使用してください。

于 2008-09-14T20:42:01.270 に答える
13

あなたが与える例は、実際には と呼ばれる python 組み込み関数divmodです。そのため、ある時点で、コア機能に含めるのに十分なpythonicであると誰かが考えました。

私にとって、それがコードをよりきれいにするなら、それはpythonicです。次の 2 つのコード ブロックを比較します。

seconds = 1234
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)

seconds = 1234
minutes = seconds / 60
seconds = seconds % 60
hours = minutes / 60
minutes = minutes % 60
于 2008-09-14T20:55:28.647 に答える
4

はい、複数の値 (つまり、タプル) を返すことは間違いなく Pythonic です。他の人が指摘しているように、Python 標準ライブラリや、評判の高い Python プロジェクトには、たくさんの例があります。2 つの追加コメント:

  1. 複数の値を返すことは、非常に便利な場合があります。たとえば、オプションでイベントを処理し (その際に何らかの値を返す)、成功または失敗も返すメソッドを考えてみましょう。これは、一連の責任パターンで発生する可能性があります。また、例のように、密接にリンクされた複数のデータを返したい場合もあります。この設定では、複数の値を返すことは、複数のメンバー変数を持つ匿名クラスの単一のインスタンスを返すことに似ています。
  2. Python のメソッド引数の処理には、複数の値を直接返す機能が必要です。たとえば、C++ では、メソッドの引数を参照によって渡すことができるため、正式な戻り値に加えて、出力値をそれらに割り当てることができます。Python では、引数は「参照渡し」で渡されます (ただし、C++ ではなく Java の意味で)。メソッドの引数に新しい値を割り当てて、メソッドのスコープ外に反映させることはできません。例えば:

    // C++
    void test(int& arg)
    {
        arg = 1;
    }
    
    int foo = 0;
    test(foo); // foo is now 1!
    

    と比べて:

    # Python
    def test(arg):
        arg = 1
    
    foo = 0
    test(foo) # foo is still 0
    
于 2008-09-15T15:47:23.777 に答える
1

タプルを返すのはクールです。また、python 2.6 で追加された新しい namedtuple にも注意してください

于 2008-09-15T15:14:04.357 に答える
1

それは間違いなくpythonicです。関数から複数の値を返すことができるという事実は、どこかで返す型のすべての組み合わせに対して構造体を定義する必要がある C のような言語の定型文です。

ただし、1 つの関数から 10 個の値などの異常な値を返すようになった場合は、それらをクラスにまとめることを真剣に検討する必要があります。

于 2008-09-15T14:46:06.810 に答える
1

OT: RSRE の Algol68 には、興味深い "/:=" 演算子があります。例えば。

INT quotient:=355, remainder;
remainder := (quotient /:= 113);

商は 3、余りは 16 です。

注: 通常、「(x/:=y)」の値は商「x」が参照によって割り当てられるため破棄されますが、RSRE の場合、返される値は剰余です。

cf整数演算 - Algol68

于 2009-03-12T21:48:42.540 に答える
0

私は Python にはかなり慣れていませんが、タプル手法は非常に Pythonic に思えます。ただし、読みやすさを向上させる別のアイデアがありました。ディクショナリを使用すると、位置ではなく名前でさまざまな値にアクセスできます。例えば:

def divide(x, y):
    return {'quotient': x/y, 'remainder':x%y }

answer = divide(22, 7)
print answer['quotient']
print answer['remainder']
于 2008-09-15T21:05:57.757 に答える
0

などの単純な関数のタプルを使用して複数の値を返すことは問題ありませんdivmod。コードが読みやすくなれば、それは Pythonic です。

戻り値が混乱し始めた場合は、関数がやりすぎていないかどうかを確認し、そうであれば分割します。大きなタプルがオブジェクトのように使用されている場合は、オブジェクトにします。また、Python 2.6 の標準ライブラリの一部となる名前付きタプルの使用を検討してください。

于 2008-09-15T14:43:01.343 に答える