[解決済み] アンパッキング、拡張アンパッキング、ネストされた拡張アンパッキング
質問
次の式を考えてみよう。なお、いくつかの式は文脈を示すために繰り返されている。
(これは長いリストです)
a, b = 1, 2 # simple sequence assignment
a, b = ['green', 'blue'] # list asqignment
a, b = 'XY' # string assignment
a, b = range(1,5,2) # any iterable will do
# nested sequence assignment
(a,b), c = "XY", "Z" # a = 'X', b = 'Y', c = 'Z'
(a,b), c = "XYZ" # ERROR -- too many values to unpack
(a,b), c = "XY" # ERROR -- need more than 1 value to unpack
(a,b), c, = [1,2],'this' # a = '1', b = '2', c = 'this'
(a,b), (c,) = [1,2],'this' # ERROR -- too many values to unpack
# extended sequence unpacking
a, *b = 1,2,3,4,5 # a = 1, b = [2,3,4,5]
*a, b = 1,2,3,4,5 # a = [1,2,3,4], b = 5
a, *b, c = 1,2,3,4,5 # a = 1, b = [2,3,4], c = 5
a, *b = 'X' # a = 'X', b = []
*a, b = 'X' # a = [], b = 'X'
a, *b, c = "XY" # a = 'X', b = [], c = 'Y'
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'
a, b, *c = 1,2,3 # a = 1, b = 2, c = [3]
a, b, c, *d = 1,2,3 # a = 1, b = 2, c = 3, d = []
a, *b, c, *d = 1,2,3,4,5 # ERROR -- two starred expressions in assignment
(a,b), c = [1,2],'this' # a = '1', b = '2', c = 'this'
(a,b), *c = [1,2],'this' # a = '1', b = '2', c = ['this']
(a,b), c, *d = [1,2],'this' # a = '1', b = '2', c = 'this', d = []
(a,b), *c, d = [1,2],'this' # a = '1', b = '2', c = [], d = 'this'
(a,b), (c, *d) = [1,2],'this' # a = '1', b = '2', c = 't', d = ['h', 'i', 's']
*a = 1 # ERROR -- target must be in a list or tuple
*a = (1,2) # ERROR -- target must be in a list or tuple
*a, = (1,2) # a = [1,2]
*a, = 1 # ERROR -- 'int' object is not iterable
*a, = [1] # a = [1]
*a = [1] # ERROR -- target must be in a list or tuple
*a, = (1,) # a = [1]
*a, = (1) # ERROR -- 'int' object is not iterable
*a, b = [1] # a = [], b = 1
*a, b = (1,) # a = [], b = 1
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
(a,b), *c = 1,2,3 # ERROR - 'int' object is not iterable
(a,b), *c = 'XY', 2, 3 # a = 'X', b = 'Y', c = [2,3]
# extended sequence unpacking -- NESTED
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
*(a,b), c = 1,2,3 # a = 1, b = 2, c = 3
*(a,b) = 1,2 # ERROR -- target must be in a list or tuple
*(a,b), = 1,2 # a = 1, b = 2
*(a,b) = 'XY' # ERROR -- target must be in a list or tuple
*(a,b), = 'XY' # a = 'X', b = 'Y'
*(a, b) = 'this' # ERROR -- target must be in a list or tuple
*(a, b), = 'this' # ERROR -- too many values to unpack
*(a, *b), = 'this' # a = 't', b = ['h', 'i', 's']
*(a, *b), c = 'this' # a = 't', b = ['h', 'i'], c = 's'
*(a,*b), = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6, 7]
*(a,*b), *c = 1,2,3,3,4,5,6,7 # ERROR -- two starred expressions in assignment
*(a,*b), (*c,) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), c = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6], c = 7
*(a,*b), (*c,) = 1,2,3,4,5,'XY' # a = 1, b = [2, 3, 4, 5], c = ['X', 'Y']
*(a,*b), c, d = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5], c = 6, d = 7
*(a,*b), (c, d) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), (*c, d) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), *(c, d) = 1,2,3,3,4,5,6,7 # ERROR -- two starred expressions in assignment
*(a,b), c = 'XY', 3 # ERROR -- need more than 1 value to unpack
*(*a,b), c = 'XY', 3 # a = [], b = 'XY', c = 3
(a,b), c = 'XY', 3 # a = 'X', b = 'Y', c = 3
*(a,b), c = 'XY', 3, 4 # a = 'XY', b = 3, c = 4
*(*a,b), c = 'XY', 3, 4 # a = ['XY'], b = 3, c = 4
(a,b), c = 'XY', 3, 4 # ERROR -- too many values to unpack
このような式の結果を手作業で正しく推論するにはどうしたらよいでしょうか?
どのように解決するのですか?
この記事の長さについては申し訳ありませんが、私は完全性を選ぶことにしました。
いくつかの基本的なルールを知れば、それを一般化するのは難しいことではありません。いくつかの例を挙げて説明することに全力を尽くします。これらを手で評価することについて話しているので、いくつかの簡単な置換ルールを提案します。基本的に、すべての反復記号が同じ方法でフォーマットされている場合、式を理解するのがより簡単であることがわかります。
解凍の目的だけのために、以下の置換は右辺にある
=
(に対して)。
rvalues
):
'XY' -> ('X', 'Y')
['X', 'Y'] -> ('X', 'Y')
もし値が展開されないことがわかったら、置換を元に戻すことになります。(詳しい説明は以下を参照してください)。
また、"naked"カンマが表示されたら、トップレベルのタプルがあることにしてください。これは左側と右側の両方で行ってください (例えば lvalues と r値 ):
'X', 'Y' -> ('X', 'Y')
a, b -> (a, b)
このような簡単なルールを念頭に置いて、いくつかの例を挙げてみましょう。
(a,b), c = "XY", "Z" # a = 'X', b = 'Y', c = 'Z'
上記の規則を適用して
"XY"
を
('X', 'Y')
に変更し、裸のカンマを括弧で囲みます。
((a, b), c) = (('X', 'Y'), 'Z')
ここでの視覚的な対応は、割り当てがどのように機能するかをかなり明白にしています。
これは誤りの例です。
(a,b), c = "XYZ"
上記の置換規則に従うと、以下のようになります。
((a, b), c) = ('X', 'Y', 'Z')
これは明らかに誤りです。ネストされた構造が一致していないのです。では、もう少し複雑な例でどのように動作するか見てみましょう。
(a,b), c, = [1,2],'this' # a = '1', b = '2', c = 'this'
上記のルールを適用すると、次のようになります。
((a, b), c) = ((1, 2), ('t', 'h', 'i', 's'))
しかし、今、構造から明らかなように
'this'
は解凍されず、直接
c
. そこで、置換を元に戻す。
((a, b), c) = ((1, 2), 'this')
では、次のように
c
をタプルで包むとどうなるか見てみましょう。
(a,b), (c,) = [1,2],'this' # ERROR -- too many values to unpack
になる
((a, b), (c,)) = ((1, 2), ('t', 'h', 'i', 's'))
ここでも、間違いは明らかです。
c
はもはや裸の変数ではなく、シーケンスの中にある変数なので、右側の対応するシーケンスが解凍され
(c,)
. しかし、シーケンスの長さが違うので、エラーになります。
では、拡張アンパックとして
*
演算子を使った拡張アンパッキングです。これは少し複雑ですが、それでもかなり簡単です。変数の前に
*
はリストになり、対応するシーケンスから変数名に割り当てられていない項目が含まれます。かなり単純な例から始めます。
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'
これは
(a, *b, c) = ('X', '.', '.', '.', 'Y')
これを分析する最も簡単な方法は、末端から作業することです。
'X'
に割り当てられるのは
a
と
'Y'
に割り当てられます。
c
. シーケンスの残りの値はリストに格納されて
b
.
のようなL値
(*a, b)
と
(a, *b)
は、上記の特殊なケースに過ぎません。2つの
*
演算子を1つの lvalue シーケンスの中に入れることはできません。このような場合、値はどこに行くのでしょうか?
(a, *b, *c, d)
-- の中で
b
または
c
? ネストされた場合について、少し考えてみます。
*a = 1 # ERROR -- target must be in a list or tuple
ここで、エラーはかなり自明なものです。ターゲット (
*a
) はタプルでなければなりません。
*a, = (1,2) # a = [1,2]
これは裸のコンマがあるからうまくいくのです。ルールを適用すると...
(*a,) = (1, 2)
以外の変数は存在しないので
*a
,
*a
は rvalue シーケンスにあるすべての値を吐き出します。を置き換えるとどうなるか。
(1, 2)
を一つの値で置き換えたらどうでしょうか?
*a, = 1 # ERROR -- 'int' object is not iterable
になる
(*a,) = 1
ここでもまた、エラーは自明です。シーケンスでないものを解凍することはできず、また
*a
には解凍するための何かが必要です。そこで、それをシーケンスに
*a, = [1] # a = [1]
と等価である。
(*a,) = (1,)
最後に、これはよくある混乱ポイントです。
(1)
と同じです。
1
-- と同じです。タプルと算術文を区別するためにコンマが必要です。
*a, = (1) # ERROR -- 'int' object is not
さて、ネストです。実はこの例はあなたの "NESTED" セクションにはありませんでした。おそらくあなたはそれがネストされていることに気づいていなかったのではないでしょうか?
(a,b), *c = 'XY', 2, 3 # a = 'X', b = 'Y', c = [2,3]
になる
((a, b), *c) = (('X', 'Y'), 2, 3)
トップレベルのタプルの最初の値が代入され、トップレベルのタプルの残りの値(
2
と
3
) に割り当てられます。
c
-- に割り当てられます。
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
*(a,b), c = 1,2,3 # a = 1, b = 2, c = 3
最初の行がなぜエラーを投げるかは、すでに上で説明したとおりです。2行目は愚かなことですが、なぜうまくいくのかを説明します。
(*(a, b), c) = (1, 2, 3)
先に説明したように、末端から作業します。
3
に割り当てられます。
c
という変数に代入され、残りの値は
*
を先行させ、この場合は
(a, b)
. ということは、次のように等価です。
(a, b) = (1, 2)
と等価であり、要素の数が適切であるため、たまたま動作します。このようなことが、実際に動作するコードに現れる理由は思いつきません。同様に
*(a, *b), c = 'this' # a = 't', b = ['h', 'i'], c = 's'
になる
(*(a, *b), c) = ('t', 'h', 'i', 's')
端から作業する。
's'
に割り当てられます。
c
に、そして
('t', 'h', 'i')
に割り当てられます。
(a, *b)
. 再び両端から作業する。
't'
に割り当てられます。
a
に、そして
('h', 'i')
はリストとしてbに代入されます。これもまた、実用的なコードに決して現れてはならない愚かな例です。
関連
-
[解決済み] 関数デコレータを作成し、それらを連鎖させるには?
-
[解決済み] staticmethodとclassmethodの違いについて
-
[解決済み] 最小限の驚き」と「変更可能なデフォルトの引数
-
[解決済み] パラメータに**(ダブルスター/アスタリスク)、*(スター/アスタリスク)がありますが、これはどういう意味ですか?
-
[解決済み] 関数呼び出しにおけるstarとdoublestarの演算子の意味は?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み】map関数を理解する
-
[解決済み] PySparkでデータフレームのカラムをString型からDouble型に変更する方法は?
-
[解決済み] 単純な文字列からtimedeltaオブジェクトを作成する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] 値で列挙名を取得する [重複]。
-
[解決済み] Ctrl-CでPythonスクリプトを終了できない
-
[解決済み] Flask でグローバル変数はスレッドセーフか?リクエスト間でデータを共有するには?
-
[解決済み] matplotlib でプロットの軸、目盛、ラベルの色を変更する方法
-
[解決済み] pycharmがタブをスペースに自動変換する
-
[解決済み] Pythonの文字列の前にあるbという接頭辞は何を意味するのですか?
-
[解決済み] djangoのQueryDictをPythonのDictに変更するには?
-
[解決済み] Pythonの辞書にあるスレッドセーフについて
-
[解決済み] Django filter queryset __in for *every* item in list