SimplePrograms の 17番目のプログラムで、気になる代入の形が出てきたので少し調べてみました。
Python の場合、代入は「代入文 (Assignmet statement) 」で規定されているようです。
https://docs.python.org/ja/3/reference/simple_stmts.html#assignment-statements
「文」だとすると
left = right = col
は出来ないと思えます。実際 JavaScript などは、代入は「式」となっています。
そこで、もう一度定義をじっくり見てみました。(インデントがいい加減ですのでご容赦ください。)
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| slicing
| "*" target
starred_expression ::= expression | (starred_item ",")* [starred_item]
starred_item ::= assignment_expression | "*" or_expr
ちゃんと見てみたら、assignment_stmt に定義されていました。
(target_list "=")+
なので、
target_list1 = target_list2 = .....
となって、代入文として連鎖代入ができるのですね。
さらに、target_list が、
target ("," target)* [","]
となっているので、
target1 , target2 , target3 .... = .......
が可能なので、
left, right = left - 1, right + 1
も出来るのですね。これは 4 lines プログラムでも出てきたのですが、右側がタプルだったのでそんなものかと勘違いしていました。
改めて、試して見ましょう。
連鎖代入は、
>>> a = b = c = 4
>>> print(a, b, c)
4 4 4
target が複数の場合は、
>>> a , b = 5 , 6
>>> print(a, b, c)
5 6 4
>>>
target は、丸括弧や、角括弧で囲めるので、
>>> (a , b ) = 7, 8
>>> print(a,b,c)
7 8 4
>>> [a , b ] = 9, 10
>>> print(a,b,c)
9 10 4
>>>
更に、定義どおり最後に "," があっても大丈夫です。
>>> a, b, c, = 10, 20, 30
>>> print(a,b,c)
10 20 30
>>> a, b, c, = 100, 200, 300,
>>> print(a,b,c)
100 200 300
>>>
target_list は、左から右へ順番に代入されるようで、target が添字表記(subscription) の時、良くわかります。
>>> print(d)
[1, 2, 3, 4, 5]
>>> i, d[ i ] = 2 , 30
>>> print(d)
[1, 2, 30, 4, 5]
>>>
"=" の右側は、4 lines プログラムのようにタプルでも良いので、リストも良いみたいです。
>>> a , b, c = 1, 2, 3
>>> a, b = (10, 20)
>>> print(a,b,c)
10 20 3
>>> a, b = [100, 200]
>>> print(a,b,c)
100 200 3
この代入するタプルやリストは、予め変数に代入しておくことが可能です。
>>> print(a, b, c)
100 200 3
>>> d = [1, 2]
>>> print(d)
[1, 2]
>>> a, b = d
>>> print(a, b, c)
1 2 3
>>>
ついでに、target がスライス表記(slicing) の場合を見てみます。
>>> d = [1, 2, 3, 4, 5, 6]
>>> d[1:3]
[2, 3]
>>> d[2:4]
[3, 4]
>>> d[2:4] = 30, 40
>>> print(d)
[1, 2, 30, 40, 5, 6]
>>> d[0:2]
[1, 2]
>>>
通常は、「最初の添字:最後の添字」となりそうですが、Python の場合は違いますね。
これは、文字列のインデックス表記と同じで、
https://docs.python.org/ja/3/tutorial/introduction.html#text
から引用すると、
----------
インデクス表記に加え、 スライス もサポートされています。インデクス表記は個々の文字を取得するのに使いますが、 スライス を使うと部分文字列を取得することができます:
>>> word = 'Python' # これは追記しました。
>>> word[0:2] # characters from position 0 (included) to 2 (excluded)
'Py'
>>> word[2:5] # characters from position 2 (included) to 5 (excluded)
'tho'
スライスの使い方をおぼえる良い方法は、インデックスが文字と文字の あいだ (between) を指しており、最初の文字の左端が 0 になっていると考えることです。そうすると、 n 文字からなる文字列中の最後の文字の右端はインデックス n となります。例えばこうです:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-----------
つまり、インデクスは要素の間を表し、この図で言えば、
[a:b]なら[インデクスの右側の文字:インデクスの左側の文字]なので、リストなら、
a の右側の要素から、b の手前の要素までを表すようです。
そのため、d[2:4] なら、先頭要素を0番目として、2番目の要素から3番目の要素までを表すのですね。
定義の最後によると、 target の頭に "*" を付けることができるようです。しかし、
>>> *c = [1, 2, 3]
File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple
>>>
なので、色々試したことろ、次のようにできることが分かりました。
>>> a, b, *c = [1, 2, 3, 4, 5, 6]
>>> print(a, b, c)
1 2 [3, 4, 5, 6]
>>>
>>> a, b, *c = 1, 2, 3, 4, 5
>>> print(a, b, c)
1 2 [3, 4, 5]
>>>
>>> a, b, *c = (1, 2, 3, 4, 5)
>>> print(a, b, c)
1 2 [3, 4, 5]
>>>
興味深いです。ちなみに、代入文で詳しそうなのを探したら、以下のものを見つけました。
Python's Assignment Operator: Write Robust Assignments
https://realpython.com/python-assignment-operator/
(中学生や高校生の方は、英語なので昔だったら諦めるところですが、現在はブラウザで翻訳できるので敷居が低くなりました。)
これからも分かるように、Python の「代入」は奥が深そうですね。
今回は、「代入文」だけになりました。次回は「リスト内包表記」に触れてみたいと思います。
Python の場合、代入は「代入文 (Assignmet statement) 」で規定されているようです。
https://docs.python.org/ja/3/reference/simple_stmts.html#assignment-statements
「文」だとすると
left = right = col
は出来ないと思えます。実際 JavaScript などは、代入は「式」となっています。
そこで、もう一度定義をじっくり見てみました。(インデントがいい加減ですのでご容赦ください。)
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| slicing
| "*" target
starred_expression ::= expression | (starred_item ",")* [starred_item]
starred_item ::= assignment_expression | "*" or_expr
ちゃんと見てみたら、assignment_stmt に定義されていました。
(target_list "=")+
なので、
target_list1 = target_list2 = .....
となって、代入文として連鎖代入ができるのですね。
さらに、target_list が、
target ("," target)* [","]
となっているので、
target1 , target2 , target3 .... = .......
が可能なので、
left, right = left - 1, right + 1
も出来るのですね。これは 4 lines プログラムでも出てきたのですが、右側がタプルだったのでそんなものかと勘違いしていました。
改めて、試して見ましょう。
連鎖代入は、
>>> a = b = c = 4
>>> print(a, b, c)
4 4 4
target が複数の場合は、
>>> a , b = 5 , 6
>>> print(a, b, c)
5 6 4
>>>
target は、丸括弧や、角括弧で囲めるので、
>>> (a , b ) = 7, 8
>>> print(a,b,c)
7 8 4
>>> [a , b ] = 9, 10
>>> print(a,b,c)
9 10 4
>>>
更に、定義どおり最後に "," があっても大丈夫です。
>>> a, b, c, = 10, 20, 30
>>> print(a,b,c)
10 20 30
>>> a, b, c, = 100, 200, 300,
>>> print(a,b,c)
100 200 300
>>>
target_list は、左から右へ順番に代入されるようで、target が添字表記(subscription) の時、良くわかります。
>>> print(d)
[1, 2, 3, 4, 5]
>>> i, d[ i ] = 2 , 30
>>> print(d)
[1, 2, 30, 4, 5]
>>>
"=" の右側は、4 lines プログラムのようにタプルでも良いので、リストも良いみたいです。
>>> a , b, c = 1, 2, 3
>>> a, b = (10, 20)
>>> print(a,b,c)
10 20 3
>>> a, b = [100, 200]
>>> print(a,b,c)
100 200 3
この代入するタプルやリストは、予め変数に代入しておくことが可能です。
>>> print(a, b, c)
100 200 3
>>> d = [1, 2]
>>> print(d)
[1, 2]
>>> a, b = d
>>> print(a, b, c)
1 2 3
>>>
ついでに、target がスライス表記(slicing) の場合を見てみます。
>>> d = [1, 2, 3, 4, 5, 6]
>>> d[1:3]
[2, 3]
>>> d[2:4]
[3, 4]
>>> d[2:4] = 30, 40
>>> print(d)
[1, 2, 30, 40, 5, 6]
>>> d[0:2]
[1, 2]
>>>
通常は、「最初の添字:最後の添字」となりそうですが、Python の場合は違いますね。
これは、文字列のインデックス表記と同じで、
https://docs.python.org/ja/3/tutorial/introduction.html#text
から引用すると、
----------
インデクス表記に加え、 スライス もサポートされています。インデクス表記は個々の文字を取得するのに使いますが、 スライス を使うと部分文字列を取得することができます:
>>> word = 'Python' # これは追記しました。
>>> word[0:2] # characters from position 0 (included) to 2 (excluded)
'Py'
>>> word[2:5] # characters from position 2 (included) to 5 (excluded)
'tho'
スライスの使い方をおぼえる良い方法は、インデックスが文字と文字の あいだ (between) を指しており、最初の文字の左端が 0 になっていると考えることです。そうすると、 n 文字からなる文字列中の最後の文字の右端はインデックス n となります。例えばこうです:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-----------
つまり、インデクスは要素の間を表し、この図で言えば、
[a:b]なら[インデクスの右側の文字:インデクスの左側の文字]なので、リストなら、
a の右側の要素から、b の手前の要素までを表すようです。
そのため、d[2:4] なら、先頭要素を0番目として、2番目の要素から3番目の要素までを表すのですね。
定義の最後によると、 target の頭に "*" を付けることができるようです。しかし、
>>> *c = [1, 2, 3]
File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple
>>>
なので、色々試したことろ、次のようにできることが分かりました。
>>> a, b, *c = [1, 2, 3, 4, 5, 6]
>>> print(a, b, c)
1 2 [3, 4, 5, 6]
>>>
>>> a, b, *c = 1, 2, 3, 4, 5
>>> print(a, b, c)
1 2 [3, 4, 5]
>>>
>>> a, b, *c = (1, 2, 3, 4, 5)
>>> print(a, b, c)
1 2 [3, 4, 5]
>>>
興味深いです。ちなみに、代入文で詳しそうなのを探したら、以下のものを見つけました。
Python's Assignment Operator: Write Robust Assignments
https://realpython.com/python-assignment-operator/
(中学生や高校生の方は、英語なので昔だったら諦めるところですが、現在はブラウザで翻訳できるので敷居が低くなりました。)
これからも分かるように、Python の「代入」は奥が深そうですね。
今回は、「代入文」だけになりました。次回は「リスト内包表記」に触れてみたいと思います。
※コメント投稿者のブログIDはブログ作成者のみに通知されます