スライスの謎、stepに負の整数を指定した場合

入門Python3 2.3.7


前回の続きになります。

stepにも負の整数を指定することができるとのことです。

その場合、startからend範囲内の文字列の末尾から左へstep数分飛んだ文字列を取れるというかんじになる・・・

・・・のだと思っていたのですが、どうやら挙動が違いました。

str = 'FooBarBaz'
result = str[3:6:-1]
print(result) # 想定ではraBと表示される
$ py main.py

といったように何も表示されません。

start=3,end=6なのでBarになり、step=-1なのでraBだと思っていたのですが違うということになります。

試しに文字列全体を対象として以下のようにして実行してみましたが

str = 'FooBarBaz'
result = str[0:9:-1]
print(result) # 想定ではzaBraBooFと表示される
$ py main.py

同じ結果になります。

ちなみに文字列を逆順にする方法として[::-1]というのが良く使われているみたいですが、確かにこのやり方だとちゃんと逆順に表示されました。

str = 'FooBarBaz'
result = str[::-1]
print(result)
$ py main.py
zaBraBooF

やってることとしては同じはずなのに何故こうなるのか・・・。

3.6.5 Documentationあたりを見ても詳しくは書いてないっぽいので色々試してみたところ、どうやらstepが負の整数の場合startとendが逆転するようです。

つまりstartからend範囲内の文字列ではなくendからstart範囲内の文字列ということになります。

str = 'FooBarBaz'
result = str[6:3:-1] # endからstart
print(result)
$ py main.py
raB

うまく想定通りに表示されました。

次に文字列全体を対象にした場合も試してみます。

str = 'FooBarBaz'
result = str[9:0:-1]
print(result) # 想定ではzaBraBooFと表示される
$ py main.py
zaBraBoo

あれ・・・何故かFが足りない。[0:9:1]であればちゃんと文字列全体が対象になるので、となると単純にstartとendが逆になる実装ではないということになります。

モウワケガワカラナイ。

一応、以下のようにすれば想定通り表示されました。

str = 'FooBarBaz'
result = str[9:-10:-1] # str[-1:-(len(str)+1):-1]でもOK
print(result)
$ py main.py
zaBraBooF

なぜendが0や-9だとうまくいかないのかさっぱりわからないし、-10だとうまくいくのもさっぱりわからない。

これ以上はもうcのソース追っかけてとかになりそうなのでこの辺で断念します。

ぼくなりの結論としてはstepに負の整数使うならstartとendは省略しとこう。

てかそれ以前に負のstepの存在なんぞもう忘れて、単に文字列の逆順得るためのイディオム=[::-1]として覚えておけばいいんじゃないのってことになりました。