python文法の謎

  • pythonにはポインタが存在する?

突然ですが、pythonってポインタが存在するんでしょうか?僕はポインタってC言語でしか見たことがなかったのでpythonでポインタもどきに出会ってしまい、困惑しています。

>>> x, *y = [1, 2, 3]
>>> x
1
>>> y
[2, 3]

これってyがリスト(0~2番)の1番目の場所を指してるポインタってこと?ふーむ*1
他にもこんなことができるのです。

>>> x, *y, z = [1, 2, 3, 4, 5]
>>> x
1
>>> y
[2, 3, 4]
>>> z
5

ほうほう、なるほど。つまりは*がついてる部分の長さは任意なのね。
で、ここからいろんなことを試していく。

>>> *a,*b = [1, 2, 3]
SyntaxError: two starred expressions in assignment
>>> *a,*b = 1, 2, 3
SyntaxError: two starred expressions in assignment

*がついてる部分の長さは任意だから、aとbのポインタがどこからどこまでなのかわかっていないのかな。2つあるともう1つのポインタは迷子になってるのかな?まぁ、なんにせよ無理です。
Learning Python(by Mark Lutz)をひも解いてみると次のように書いてありました。

>>> seq
[1, 2, 3, 4]
Finally, errors can still be triggered if there is more than one starred name, if there are too few values and no star (as before), and if the starred name is not itself coded inside a sequence:
>>> a, *b, c, *d = seq
SyntaxError: two starred expressions in assignment

>>> a, b = seq
ValueError: too many values to unpack

ははぁ・・・、2つ以上のスターは使うなと。で他にも目についた変なこととして

>>> *a,=range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> *a = [1,2,3,4]
SyntaxError: starred assignment target must be in a list or tuple
>>> a,=[1]
>>> a
1
>>> a,=[1,2,3]
Traceback (most recent call last):
  File "<pyshell#142>", line 1, in <module>
    a,=[1,2,3]
ValueError: too many values to unpack (expected 1)

>>> x,*y,z='abc'
>>> x
'a'
>>> y
['b']
>>> z
'c'
>>> *y
SyntaxError: can use starred expression only as assignment target
>>> print(*y)
b

カンマにいかほどの意味があるのかは現時点では不明。どうなってるのかなぁ
あと、なんでprintで表示できるのに単体ではダメなんだ?お前strオブジェクトなんだろ、前出て来いよ。
というかzは'c'だからstrオブジェクトだろうけど*yのオブジェクトって何だろう。

>>> type(z)
<class 'str'>
>>> type(y)
<class 'list'>
>>> type(*y)
<class 'str'>

あれ、strだた。ならなぜ出てきてくれないのか。ただ注意しなくてはいけないのは、次のような場合にはエラーになるということ。

>>> *a,=1,2
>>> a
[1, 2]
>>> type(*a)
Traceback (most recent call last):
  File "<pyshell#170>", line 1, in <module>
    type(*a)
TypeError: type() takes 1 or 3 arguments
>>> a=[1]
>>> type(*a)
<class 'int'>

このようにリストの要素が複数あれば、タイプを聞いてもエラー。単体ならばいける。

最後にもう一つ

>>> a=b=[1]
>>> b.append(3)
>>> a,b
([1, 3], [1, 3])
>>> a=b=[1]
>>> b+=[3]
>>> a,b
([1, 3], [1, 3])
>>> a=b=[1]
>>> b=b+[3]
>>> a,b
([1], [1, 3])

ここで、コメントしておきたいのは、なぜ最後の場合のみaに追加の命令が反映されていないのかということです。
奥が深いのか、それとも粗さの表れなのか、まー専門家ではないので良し悪しはわかりませんね。

*1:python3.3.2での実行結果です。python2.7.6では、エラーになりました。