web-dev-qa-db-ja.com

同時に複数の変数を宣言するよりエレガントな方法

「同時に」複数の変数を宣言するには、次のようにします。

a, b = True, False

しかし、もっと多くの変数を宣言する必要がある場合、それは次第にエレガントになります。

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True

これを行うためのより良い/エレガントな/便利な方法はありますか?

これは非常に基本的なものでなければなりませんが、変数を保存するためにリストまたはタプルを使用した場合、私が役立つようにどのようにアプローチする必要がありますか:

aList = [a,b]

有効ではありません、私はしなければなりません:

a, b = True, True

または私は何が欠けていますか?

119
Trufa

他の人が示唆しているように、10個の異なるローカル変数をブール値で使用することがルーチンを書く最良の方法であるとは考えられません(特にそれらが本当に1文字の名前を持っている場合:)

何をしているのかにもよりますが、代わりに辞書を使用するのが理にかなっています。たとえば、1文字のフラグのセットに対してブールプリセット値を設定する場合は、次のようにします。

>>> flags = dict.fromkeys(["a", "b", "c"], True)
>>> flags.update(dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

必要に応じて、単一の割り当てステートメントでそれを行うこともできます。

>>> flags = dict(dict.fromkeys(["a", "b", "c"], True),
...              **dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

dictの2番目のパラメーターは、このために完全に設計されているわけではありません。実際には、d=Falseなどのキーワード引数を使用して、辞書の個々の要素をオーバーライドできます。上記のコードは、**に続く式の結果を キーワード引数 のセットに爆発させ、呼び出された関数に渡します。これは確かに辞書を作成するための信頼できる方法であり、人々は少なくともこのイディオムを受け入れているように見えますが、一部の人はそれをUnpythonicとみなすかもしれません。 </disclaimer>


このパターンを頻繁に使用する場合に最も直感的と思われるもう1つのアプローチは、フラグ名(単一文字の文字列)にマッピングされたフラグ値(TrueFalse)のリストとしてデータを定義することです。次に、このデータ定義を、フラグ名をフラグ値にマッピングする逆辞書に変換します。これは、ネストされたリストの内包表記を使用して非常に簡潔に行うことができますが、非常に読みやすい実装を次に示します。

>>> def invert_dict(inverted_dict):
...     elements = inverted_dict.iteritems()
...     for flag_value, flag_names in elements:
...         for flag_name in flag_names:
...             yield flag_name, flag_value
... 
>>> flags = {True: ["a", "b", "c"], False: ["d", "e"]}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

関数invert_dictジェネレーター関数 です。 Itgenerates、またはyields—それが意味する—キーと値のペアの値を繰り返し返します。これらのキーと値のペアは、最初のflags辞書の2つの要素の内容の逆です。それらはdictコンストラクターに供給されます。この場合、dictコンストラクターは、引数として辞書ではなく イテレーター が渡されるため、上記とは異なる動作をします。


@Chris Lutzのコメントを参考にしてください:1文字の値にこれを実際に使用する場合は、実際に行うことができます

>>> flags = {True: 'abc', False: 'de'}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

これは、Python文字列が iterable であるため、値ごとに移動できるためです。文字列の場合、値は文字列内の個々の文字です。したがって、forループで使用されているこの場合のように、イテレート可能オブジェクトとして解釈される場合、['a', 'b', 'c']'abc'は実質的に同等です。別の例は、 Tuple のような反復可能なものを受け取る関数に渡される場合です。

直観的に読み取れないため、私は個人的にこれを行いません。文字列を見ると、リストとしてではなく単一の値として使用されることを期待しています。それで、最初の行を見て、「わかりました。TrueフラグとFalseフラグがあります」と思います。可能性はありますが、私はそれが進むべき道だとは思いません。良い面としては、イテラブルとイテレータの概念をより明確に説明するのに役立つかもしれません。


実際に辞書を返すように関数invert_dictを定義することも悪い考えではありません。ルーチンがどのように機能するかを説明するのは実際には役立たないので、私はほとんどそれをしなかった。


どうやらPython 2.7には辞書の理解があり、その関数を実装するための非常に簡潔な方法になります。 Python 2.7がインストールされていないので、これは読者への課題として残されています:)

また、汎用性の高い itertools モジュールの一部の関数を組み合わせることもできます。彼らが言うように、 それを行うには複数の方法があります 。待ってください、Python人々はそれを言わない。まあ、とにかくそれは本当です。これを行うために One Obvious Way が存在するように、Guidoが私たちに辞書の理解を与えたと思います。

46
intuited
a, b, c, d, e, g, h, i, j = (True,)*9
f = False
205
Shariq

リスト/ディクショナリを使用するか、独自のクラスを定義して、定義しているものをカプセル化しますが、これらの変数がすべて必要な場合は次のようにします。

a = b = c = d = e = g = h = i = j = True
f = False
48
yan

これは、@ Jeff M の詳細と私のコメントです。

これを行うとき:

a, b = c, d

Tupleのパックとアンパックで機能します。梱包と開梱の手順を分けることができます。

_ = c, d
a, b = _

最初の行は、2つの要素を持つ_というTupleを作成します。1つ目はcの値で、2つ目はdの値です。 2行目は_ Tupleを変数aおよびbにアンパックします。これにより、1つの大きな行が細分化されます。

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True, True, True, True

2つの小さな行に:

_ = True, True, True, True, True, False, True, True, True, True
a, b, c, d, e, f, g, h, i, j = _

最初の行とまったく同じ結果が得られます(1つの部分に値または変数を追加したが、他の部分の更新を忘れた場合の同じ例外を含む)。ただし、この特定のケースでは、おそらく yanの答え が最適です。

値のリストがある場合でも、それらを解凍できます。最初にそれをTupleに変換するだけです。たとえば、次の例では、それぞれajにそれぞれ0〜9の値を割り当てます。

a, b, c, d, e, f, g, h, i, j = Tuple(range(10))

編集:要素5(変数f)を除くすべてをtrueとして割り当てる巧妙なトリック:

a, b, c, d, e, f, g, h, i, j = Tuple(x != 5 for x in range(10))
9
Chris Lutz

人々が「リストまたはタプルまたはその他のデータ構造を使用する」ことを提案しているとき、彼らが言っているのは、気になる多くの異なる値がある場合、それらをすべてローカル変数として個別に命名するのが最善の方法ではないかもしれないということです物事をするために。

代わりに、それらを1つのローカル変数に格納できる大きなデータ構造にまとめたい場合があります。

intuitedはこれに辞書を使用する方法を示し、Chris Lutzは個別の変数にアンパックする前に一時記憶域にTupleを使用する方法を示しましたが、考慮する別のオプションは、collections.namedtupleを使用して値をより永続的にバンドルすることです。

だからあなたは次のようなことをするかもしれません:

# Define the attributes of our named Tuple
from collections import namedtuple
DataHolder = namedtuple("DataHolder", "a b c d e f g")

# Store our data
data = DataHolder(True, True, True, True, True, False, True)

# Retrieve our data
print(data)
print(data.a, data.f)

もちろん、実際のコードでは、「DataHolder」やアルファベット文字よりも意味のある名前を使用することが望ましいでしょう。

5
ncoghlan

実際に問題は何ですか?

本当に必要または必要な場合10 abcde =、fghijaと書くbと書くc .....

値がすべて異なる場合は、exempleを記述する必要があります。

a = 12
b= 'Sun'
c = A() #(where A is a class)
d = range(1,102,5)
e = (line in filehandler if line.rstrip())
f = 0,12358
g = True
h = random.choice
i = re.compile('^(!=  ab).+?<span>')
j = [78,89,90,0]

つまり、「変数」を個別に定義します。

または、別の記述を使用すると、_を使用する必要はありません。

a,b,c,d,e,f,g,h,i,j =\
12,'Sun',A(),range(1,102,5),\
(line for line in filehandler if line.rstrip()),\
0.12358,True,random.choice,\
re.compile('^(!=  ab).+?<span>'),[78,89,90,0]

または

a,b,c,d,e,f,g,h,i,j =\
(12,'Sun',A(),range(1,102,5),
 (line for line in filehandler if line.rstrip()),
 0.12358,True,random.choice,
 re.compile('^(!=  ab).+?<span>'),[78,89,90,0])

それらのいくつかが同じ値を持たなければならない場合、それは書くには長すぎるという問題です

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True 

その後、あなたは書くことができます:

a=b=c=d=e=g=h=i=k=j=True
f = False

私はあなたの問題が正確に何であるか理解していません。コードを記述したい場合は、指示と定義の記述に必要な文字を使用する必要があります。ほかに何か ?

あなたの質問は、あなたが何かを誤解している兆候ではないのだろうか。

a = 10を書き込むと、変数を作成しない「値を変更できるメモリの塊」の意味で。この指示:

  • タイプintegerおよび値10のオブジェクトの作成、および現在のネームスペースでこのオブジェクトと名前「a」のバインディングをトリガーします

  • または、名前空間の名前「a」をオブジェクトに再割り当てします1(「a」は以前に別のオブジェクトにバインドされていたため)

私は、10個の識別子a、b、cを定義するユーティリティがFalseまたはTrueを指しているのを見ていないからだと言います。実行中にこれらの値が変わらない場合、なぜ10個の識別子が必要ですか?そして、それらが変更される場合、なぜ最初に識別子を定義するのですか?

あなたの質問は私には奇妙に見える

4
eyquem

あなたは私に間違った方法であなたの問題に近づいているように聞こえます。

タプルを使用するようにコードを書き直すか、すべてのデータを保存するクラスを作成します。

2
richo

私はトップ投票の回答が好きです。ただし、示されているリストには問題があります。

  >> a, b = ([0]*5,)*2
  >> print b
  [0, 0, 0, 0, 0]
  >> a[0] = 1
  >> print b
  [1, 0, 0, 0, 0]

詳細は (here) で説明しますが、要点はaba is bTrueを返す同じオブジェクトであるということです(id(a) == id(b)と同じ)。したがって、インデックスを変更すると、リンクされているため、abの両方のインデックスが変更されます。これを解決するには、 (source) を実行します

>> a, b = ([0]*5 for i in range(2))
>> print b
[0, 0, 0, 0, 0]
>> a[0] = 1
>> print b
[0, 0, 0, 0, 0]

これは、トップアンサーのバリアントとして使用でき、「望ましい」直感的な結果が得られます。

>> a, b, c, d, e, g, h, i = (True for i in range(9))
>> f = (False for i in range(1)) #to be pedantic
0
Novice C