Effective Python
読書会 #1
オズ@Wizard_of_Oz__
自己紹介
• オズ @Wizard_of_Oz__
• 拝承系エンジニア
• Python歴一ヶ月なんでイジメないでください(>_<)
Effective
Python
項目5
シーケンスをどのようにスライスするか知っておく
シーケンスをスライスする構文
• シーケンスのスライス
– シーケンスの部分に簡単にアクセス
– 組み込みではlist, str, bytesで利用可
>>> S = [‘h’, ‘o’, ‘g’, ’e’, ’f’, ’u’, ’g’, ’a’]
>>> print(s[2:6])
[‘g’, ’e’, ’f’, ’u’]
• 構文
somelist[start:end]
シーケンスをスライスする構文
somelist[start:end]
s[2:6]
0
h
1
o
2
g
3
e
4
f
5
u
6
g
7
a
含む 含まない
シーケンスをスライスする構文
somelist[ : ]
s[:4] #[‘h’, ‘o’, ‘g’, ’e’]
0
h
1
o
2
g
3
e
4
f
5
u
6
g
7
a
0 len(s)余分な添字は省く
シーケンスをスライスする構文
・要素にはマイナスも指定可能
s[3:-3] #[’e’, ’f’]
-8
0
h
-7
1
o
-6
2
g
-5
3
e
-4
4
f
-3
5
u
-2
6
g
-1
7
a
シーケンスをスライスする構文
・-nを使うとき、n=0がくると予想外の結果に
s[-n:] # s[:]
-8
0
h
-7
1
o
-6
2
g
-5
3
e
-4
4
f
-3
5
u
-2
6
g
-1
7
a
シーケンスをスライスする構文
a[:]
a[:5]
a[:-1]
a[4:]
a[-3:]
a[2:5]
a[2:-1]
a[-3:-1]
シーケンスをスライスする構文
a[:] #[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
a[:5] #[‘a’, ‘b’, ‘c’, ’d’, ’e’]
a[:-1] #[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’]
a[4:] # [’e’, ’f’, ’g’, ’h’]
a[-3:] # [’f’, ’g’, ’h’]
a[2:5] # [‘c’, ’d’, ’e’]
a[2:-1] # [‘c’, ’d’, ’e’, ’f’, ’g’]
a[-3:-1] # [’f’, ’g’]
a[:]
a[:5]
a[:-1]
a[4:]
a[-3:]
a[2:5]
a[2:-1]
a[-3:-1]
範囲を超えた添字
• リストの境界を超えた添字も適切に扱われる
input = a[:20]
• 直接アクセスは例外
a[20]
>>>
IndexError: list index out of range
スライスはコピペ(not カット&ペースト)
>>> a = [‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
>>> b = a[:4] # [‘a’, ‘b’, ‘c’, ’d’]
>>> b[1] = 99
>>> print(b)
[‘a’, 99, ‘c’, ’d’]
>>> print(a)
[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
代入によって適切に伸び縮み
• 代入するスライスの長さは同じでなくて良い
>>> b = a[:]
>>> b[1:-1] = [1, 2, 3]
>>> print(a)
[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
>>> print(b)
[‘a’, 1, 2, 3, ’h’]
代入によって適切に伸び縮み
>>> b = a
>>> print(a)
[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
>>> a[:] = [1, 2, 3]
>>> print(a)
[1, 2, 3]
>>> assert a is b
>>> (no assertion)
まとめ
• 冗長を避ける “[0:”や”len()]”を使用しない
• 境界外の添字が許される a[:20] #a = [1, 2, 3]
• 代入は長さが違っても合わせてくれる #a[1:10] = [1, 2]
Effective
Python
項目6
1つのスライスでは、start, end, strideを使わない
スライスの増分を設定できる
somelist[start:end:stride]
a[::2] #[‘a’, ‘c’, ’e’, ’g’]
0
a
1
b
2
c
3
d
4
e
5
f
6
g
7
h
増分
スライスの増分を設定できる
a[::2] #[‘a’, ‘c’, ’e’, ’g’]
a[1::2] #[‘b’, ‘d’, ’f’, ’h’]
0
a
1
b
2
c
3
d
4
e
5
f
6
g
7
h
a b c d e f g h
strideを使ったよくある技法
>>> a = ‘abcdefgh’
>>> a[::-1]
‘hgfedcba’
☆Unicode文字列にはうまく動かない
>>> s = ‘ほげ’.encode(‘utf-8’)
>>> x = s[::-1]
>>> x.decode(‘utf-8’)
使用例
a = [‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
a[::2]
a[::-2]
a[2::2]
a[-2::-2]
a[-2:2:-2]
a[2:2:-2]
1つのスライスで
start, end, strideを使わない
• start, endと一緒にstrideを使わない
• strideはできるだけ正の値に
• どうしても組み合わせる必要があるときは
strideのみとスライスのみに分けて使う
>>> a #[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
>>> a[2:-2:2] #[‘c’, ’e’]
>>> b = a[::2] #[‘a’, ‘c’, ’e’, ’g’]
>>> c = b[1:-1] #[‘c’, ’e’]
1つのスライスで
start, end, strideを使わない
• どうしても組み合わせる必要があるときは
strideのみとスライスのみに分けて使う
>>> a #[‘a’, ‘b’, ‘c’, ’d’, ’e’, ’f’, ’g’, ’h’]
>>> a[2:-2:2] #[‘c’, ’e’]
>>> b = a[::2] #[‘a’, ‘c’, ’e’, ’g’]
>>> c = b[1:-1] #[‘c’, ’e’]
>>> b = a[2:-2] #[‘c’, ‘d’, ’e’, ’f’]
>>> c = b[::2] #[‘c’, ’e’]
まとめ
• start, end, strideを指定すると分かりにくいことがある
• strideはできるだけ正の値
• strideはstart, endどちらか一方のみと一緒に使う
• どうしてもすべて必要な時は2行に分ける
– もしくはitertoolsのisliceメソッドを使う (start, end, strideに負の値を許さない)
– (項目46:組み込みアルゴリズムとデータ構造を使う 参照)

Effective python #5, #6