それをサポートする言語で複数の値を返す標準的な方法はよくありますサンプリング。
この簡単な例を考えてください。
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0,y1,y2)
ただし、返される値の数が増えるにつれて、これはすぐに問題になります。 4つか5つの値を返したい場合はどうしますか?確かに、それらを組み合わせていくことはできますが、どの値がどこにあるかを忘れがちです。あなたがそれらを受け取りたいと思うところはどこでもそれらを開梱することもかなり醜いです。
次の論理的なステップはある種の 'record notation'を導入することにあるようです。 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(object):
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によって提供される追加機能が1つあります。__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__
インスタンスごとには作成されません。
私が見落としていたもう一つの提案はビルトカゲから来ている:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
これは私の最も好きな方法です。私はHaskellに触れることに汚染されていると思いますが、混合型リストのアイデアは常に私にとって不快に感じました。この特定の例では、リストは混合型ではありませんが、それも可能性があります。このように使われるリストは、私が言うことができる限り、タプルに関して実際には何も得られません。 Pythonのリストとタプルの唯一の本当の違いは、リストが変わりやすいタラスはそうではありません。私は個人的には関数型プログラミングからの慣習を引き継ぐ傾向があります。同じ型の要素をいくつでもリストに使用し、あらかじめ決められた型の要素を固定数だけ使用するためにタプルを使用します。
長い序文の後、避けられない問題があります。どの方法が良いですか?
セットアップ作業が少なくて済むので、私は一般的に自分で辞書を使うようになりました。しかし、型の観点からすると、クラスルートを避けた方がよい場合があります。辞書が表すものを混同しないようにするためです。一方、Pythonコミュニティには、次のようなことを感じる人がいます。暗黙のインタフェースは明示的なインタフェースよりも優先されるべきですこれは、同じ属性が常に同じ意味を持つという規約に基本的に頼っているからです。
では、Pythonではどうやって複数の値を返すのでしょうか。
名前付きタプルこの目的のために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 collections.NamedTuple
name: str
id: int = 3 # default value
employee = Employee('Guido')
assert employee.id == 3
namedtuple
以下のためのメモリフットプリントが小さい質量結果(DBクエリの結果など、タプルの長いリスト)。個々の項目については(問題の関数が頻繁に呼び出されない場合)、辞書とクラスも同様に問題ありません。しかし、この場合もnamedtuplesは優れた/より良いソリューションです。 - Lutz Precheltp=collections.namedtuple('point','x,y')(1,2)
- Dave Xnamedtuple
定義(各呼び出しは新しいものを作成します)、namedtuple
classはCPUとメモリの両方で比較的高価であり、すべてのクラス定義は本質的に巡回参照を含みます(CPythonでは、それらが解放されるまで巡回GCの実行を待っています)。それはまたそれを不可能にしますpickle
クラス(したがって、でインスタンスを使用することは不可能です)multiprocessing
ほとんどの場合)。私の3.6.4 x 64でクラスを作成するたびに約0.337 msを消費し、1 KB未満のメモリを占有するため、インスタンスの節約になります。 - ShadowRanger
小さなプロジェクトでは、タプルを使うのが一番簡単だと思います。それを管理するのが難しくなり過ぎると(そして以前はそうではありませんが)私は物事を論理構造にグループ化し始めますが、辞書とReturnValueオブジェクトのあなたの提案した使い方は間違っていると思います
キーy0、y1、y2などを持つ辞書を返すことは、タプルを超える利点を提供しません。プロパティ.y0 .y1 .y2などを持つReturnValueインスタンスを返すことは、タプルよりも有利な点はありません。あなたがどこにでも行きたいのなら、物事の命名を始める必要があります、そしてそれでもタプルを使ってそれをすることができます:
def getImageData(filename):
[snip]
return size, (format, version, compression), (width,height)
size, type, dimensions = getImageData(x)
私見、タプルを超えた唯一の良いテクニックは、あなたがから得るように、適切なメソッドとプロパティを持つ実際のオブジェクトを返すことです。re.match()
またはopen(file)
。
size, type, dimensions = getImageData(x)
そして(size, type, dimensions) = getImageData(x)
?つまり、タプル割り当ての左辺をラップしても違いはありますか? - Reb.Cabin(1)
intです。(1,)
または1,
タプルです。 - phil
多くの答えはあなたが辞書やリストのようなある種のコレクションを返す必要があることを示唆しています。余分な構文を省略して、単に戻り値をコンマ区切りで書き出すことができます。注:これは技術的にはタプルを返します。
def f():
return True, False
x, y = f()
print(x)
print(y)
を与えます:
True
False
type(f())
戻る<class 'tuple'>
。 - Igortuple
アスペクト明示返品することは重要ではありません。tuple
、これは複数値の期間を返すための慣用句です。スワップイディオムで親を省略するのと同じ理由で、x, y = y, x
、複数の初期化x, y = 0, 1
など確かにそれは作るtuple
しかし、それを明示的にする理由はありません。tuple
ポイントはまったくありません。 Pythonチュートリアル多重代入を導入しますそれが触れさえするずっと前にtuple
s。 - ShadowRanger
私はその辞書に投票します。
2〜3個以上の変数を返す関数を作成すると、辞書にまとめられることがわかりました。さもなければ私は私が戻ってきたものの順序と内容を忘れがちです。
また、「特別な」構造を導入すると、コードを理解しにくくなります。 (他の誰かがコードを検索してそれが何であるかを調べる必要があります)
型が気になる場合は、「x-values list」などの説明的な辞書キーを使用してください。
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0':y0, 'y1':y1 ,'y2':y2 }
result = g(x); other_function(result)
- monkut
別の選択肢はジェネレータを使うことです。
>>> def f(x):
y0 = x + 1
yield y0
yield x * 3
yield y0 ** 4
>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296
IMHOタプルが通常は最良ですが、返される値がクラス内のカプセル化の候補である場合を除きます。
yield
? - CoreDumpError
タプルが「自然」と感じるときはいつでもタプルを使用することを好みます。座標は典型的な例で、ここでは別々のオブジェクトはそれら自身の上に立つことができます。 1軸のみのスケーリング計算では、順序は重要です。注:グループの意味に悪影響を及ぼさずにアイテムをソートまたはシャッフルできる場合は、おそらくタプルを使用しないでください。
グループ化されたオブジェクトが常に同じではない場合に限り、辞書を戻り値として使用します。オプションのメールヘッダを考えてください。
グループ化されたオブジェクトがグループ内で固有の意味を持つ場合や、独自のメソッドを持つ完全なオブジェクトが必要な場合は、クラスを使用します。
私は好きです
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0':y0, 'y1':y1 ,'y2':y2 }
他のものはすべて同じことをするための追加のコードにすぎません。
>>> def func():
... return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3
Pythonのタプル、辞書、およびオブジェクトは、プログラマーに、形式と簡潔なデータ構造(「もの」)の利便性との間の円滑なトレードオフを提供します。私にとって、ものを表現する方法の選択は、主にその構造をどのように使用するかによって決まります。 C ++では、使用するのが一般的な規約です。struct
データのみの項目の場合class
メソッドを持つオブジェクトに対しては、メソッドに合法的にメソッドを置くことはできますがstruct
;私の習慣はPythonでも似ています。dict
そしてtuple
代わりにstruct
。
座標セットには、tuple
点ではなくclass
またはdict
(そしてあなたが使用できることに注意してくださいtuple
辞書のキーとしてdict
s優れたスパース多次元配列を作成します。
私がもののリストを反復処理するつもりなら、私は解凍することを好みますtuple
反復処理中のs
for score,id,name in scoreAllTheThings():
if score > goodScoreThreshold:
print "%6.3f #%6d %s"%(score,id,name)
...オブジェクトのバージョンは読みやすくなっています。
for entry in scoreAllTheThings():
if entry.score > goodScoreThreshold:
print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)
...はもちろんdict
。
for entry in scoreAllTheThings():
if entry['score'] > goodScoreThreshold:
print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])
そのことが広く使われていて、コードの複数の場所でそれに似たような簡単でない操作をしているのであれば、それを適切なメソッドを持つクラスオブジェクトにすることは通常価値があります。
最後に、Python以外のシステムコンポーネントとデータをやり取りする場合は、ほとんどの場合、それらをdict
JSONシリアライゼーションに最も適しているからです。
一般的に、「特殊な構造」は実際にはオブジェクトの賢明な現在の状態であり、独自のメソッドがあります。
class Some3SpaceThing(object):
def __init__(self,x):
self.g(x)
def g(self,x):
self.y0 = x + 1
self.y1 = x * 3
self.y2 = y0 ** y3
r = Some3SpaceThing( x )
r.y0
r.y1
r.y2
可能な限り無名構造体の名前を見つけるのが好きです。意味のある名前は物事をより明確にします。
S.Lottによる名前付きコンテナクラスの提案に+1
Python 2.6以降では、名前付きタプルこれらのコンテナクラスを簡単に作成するための便利な方法を提供します、そしてその結果は「軽量で通常のタプルより多くのメモリを必要としません」です。
Pythonのような言語では、新しいクラスを作成するよりもオーバーヘッドが少ないため、通常は辞書を使用します。
しかし、私が自分自身が同じ変数のセットを絶えず返すのであれば、それはおそらく私が除外する新しいクラスを含みます。
関数から値を渡したり返したりするには、辞書を使用します。
で定義されているように変数形式を使用する形。
form = {
'level': 0,
'points': 0,
'game': {
'name': ''
}
}
def test(form):
form['game']['name'] = 'My game!'
form['level'] = 2
return form
>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}
これは私にとっても処理ユニットにとっても最も効率的な方法です。
1つだけポインタを渡し、1つだけポインタを戻す必要があります。
コードを変更するたびに、関数の引数(数千個)を変更する必要はありません。
「最高」は部分的に主観的な決定です。不変が許容できる一般的な場合には、小さな戻り値集合にタプルを使用します。可変性が必要条件ではない場合、タプルは常にリストよりも優先されます。
より複雑な戻り値の場合、または形式が重要な場合(つまり、高価値のコード)の場合は、名前付きタプルの方が適しています。最も複雑な場合では、通常オブジェクトが最善です。しかし、それは本当に重要な状況です。オブジェクトを返すことが理にかなっているのであれば、それが関数の最後に自然にあるもの(例えば、Factoryパターン)であれば、そのオブジェクトを返します。
賢人が言ったように:
時期尚早の最適化は、すべての悪の根源です(または少なくともほとんどの それは)プログラミングで。
y3
しかし、y3がグローバルと宣言されていない限り、これは次のようになります。NameError: global name 'y3' is not defined
多分ちょうど使用しなさい3
? - hetepeperfan