はじめに
こんにちは!Python学習に励む皆さんの並走者として、今日も学習記録をお届けします。
今回も引き続き、Udemyの「現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル」(講師: 酒井潤 さん)を受講しています。学習4日目となる今日のテーマはリスト型です。Pythonの中でも特によく使うデータ構造で、盛りだくさんな内容でした!
今日学んだこと
- リスト型の基本(インデックス・スライス)
- リストの要素の追加・削除・変更
- リストに使えるメソッドいろいろ
- リストのコピーの落とし穴
- リストの実際の使い所
1. リスト型
リストは複数の値をまとめて管理できるデータ型です。[] で囲んで作ります。
l = [1, 2, 20, 5, 6, 7, 8]
# インデックスで要素を取得
print(l[0]) # → 1(先頭)
print(l[-1]) # → 8(末尾は -1 で取れる!)
# スライスで範囲取得
print(l[:2]) # → [1, 2]
print(l[2:5]) # → [20, 5, 6]
print(l[:]) # → [1, 2, 20, 5, 6, 7, 8](全コピー)
💡 マイナスインデックスが便利! l[-1] で末尾の要素が取れます。リストの長さを調べなくていいので楽です。
n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# ステップを指定したスライス
print(n[::2]) # → [1, 3, 5, 7, 9](1つ飛ばし)
print(n[::-1]) # → [10, 9, 8, 7, 6, 5, 4, 3, 2, 1](逆順!)
⚠️ list["abcdefg"] はエラーになりますが、list("abcdefg") は文字列を1文字ずつのリストに変換してくれます。
print(list("abcdefg")) # → ['a', 'b', 'c', 'd', 'e', 'f', 'g']
リストの中にリストを入れる「ネストリスト」も可能です。
a = ["a", "b", "c"]
b = [1, 2, 3]
x = [a, b]
print(x[0][1]) # → 'b'(外側のインデックス → 内側のインデックス)
print(x[1][0]) # → 1
2. リストの操作
リストは 変更可能 なので、要素を後から書き換えたり、追加・削除できます。
s = ["a", "b", "c", "d", "e", "f", "g"]
# 要素の書き換え
s[0] = "A"
print(s) # → ['A', 'b', 'c', 'd', 'e', 'f', 'g']
# スライスで範囲ごと書き換え
s[2:5] = ["C", "D", "E"]
print(s) # → ['A', 'b', 'C', 'D', 'E', 'f', 'g']
# スライス範囲を空リストにすれば削除
s[2:5] = []
print(s) # → ['A', 'b', 'f', 'g']
# 全要素を削除
s[:] = []
print(s) # → []
要素の追加・削除には専用のメソッドも使えます。
n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
n.append(100) # 末尾に追加
n.insert(0, 200) # 先頭(インデックス0)に追加
print(n) # → [200, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100]
n.pop() # 末尾を取り出して削除
n.pop(0) # 先頭を取り出して削除
del n[0] # インデックス指定で削除
# 値を指定して削除(最初に見つかった1個だけ)
n = [1, 2, 2, 2, 3]
n.remove(2)
print(n) # → [1, 2, 2, 3]
⚠️ remove() は存在しない値を指定すると ValueError になるので注意!
リスト同士は + で結合できます。
a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]
x = a + b # 新しいリストを作る
a += b # a 自体を伸ばす(extend と同じ効果)
b.extend(a) # b に a の要素を全部追加
3. リストのメソッド
リストには便利なメソッドが揃っています。
r = [1, 2, 3, 4, 5, 1, 2, 3]
# 要素の位置を調べる(第2引数で検索開始位置を指定)
print(r.index(3, 3)) # → 7(インデックス3以降で最初の3)
# 要素の個数を数える
print(r.count(3)) # → 2
# in演算子で存在チェック
if 5 in r:
print("exist") # → exist(5はある)
if 100 in r:
print("exist") # 出力なし(100はない)
# ソート
r.sort() # 昇順
r.sort(reverse=True) # 降順
r.reverse() # 現在の順番を逆にするだけ
💡 文字列との連携も便利!
s = "My name is Mike."
# 空白で分割してリストにする
to_split = s.split(" ")
print(to_split) # → ['My', 'name', 'is', 'Mike.']
# リストを指定の区切り文字で結合して文字列に戻す
x = " #### ".join(to_split)
print(x) # → 'My #### name #### is #### Mike.'
split() と join() はセットで覚えると応用範囲が広がります!
4. リストのコピー
今日の中で一番「なるほど!」と思ったのがここです。
# NG例:= で代入するとコピーではなく「同じリストを指す」だけ
i = [1, 2, 3, 4, 5]
j = i
j[0] = 100
print("j =", j) # → j = [100, 2, 3, 4, 5]
print("i =", i) # → i = [100, 2, 3, 4, 5] ← iまで変わった!
j = i とすると、j と i は同じリストオブジェクトを指しているため、片方を変えるともう片方も変わってしまいます。
# OK例1: .copy() を使う
x = [1, 2, 3, 4, 5]
y = x.copy()
y[0] = 100
print("y =", y) # → y = [100, 2, 3, 4, 5]
print("x =", x) # → x = [1, 2, 3, 4, 5] ← 影響なし!
# OK例2: スライスで全コピー
a = [1, 2, 3, 4, 5]
b = a[:]
b[0] = 100
print("b =", b) # → b = [100, 2, 3, 4, 5]
print("a =", a) # → a = [1, 2, 3, 4, 5] ← 影響なし!
ちなみに int のような数値型は = でコピーしても問題ありません。数値は変更できない(イミュータブル)なので、代入時に別のオブジェクトが作られるためです。
5. リストの使い所
最後に、リストを実際のロジックで活用する例を学びました。席の空き管理のシミュレーションです。
seat = []
min_count = 0
max_count = 5
# 席が空いているか確認
print(min_count <= len(seat) < max_count) # → True(空席あり)
# 人が来るたびに追加
seat.append("p")
seat.append("p")
seat.append("p")
seat.append("p")
seat.append("p")
print(min_count <= len(seat) < max_count) # → False(満席!)
# 席が空いた
seat.pop(0)
print(min_count <= len(seat) < max_count) # → True(また空席あり)
💡 リストの append() と pop() を使うだけで、キューのような動きが実現できます。シンプルですが実用的な例でした。
感想
今日の学習でいちばん印象に残ったのは、リストのコピーの挙動です。j = i としたとき、てっきり「コピー」されると思っていたのですが、実際には同じリストを「指し示しているだけ」だと知って驚きました。これは知らずにいると、バグの原因になりそうだなと感じました。copy() か [:] を使うことで安全にコピーできると覚えておこうと思います。
split() と join() の組み合わせも面白かったです。文字列とリストを行き来できるというのは、文字列処理をするときにかなり役立ちそうです。
リスト一つとっても、こんなに奥が深いとは思いませんでした。覚えることは多いですが、一つひとつ確認しながら書いていると少しずつ手に馴染んできます。同じく学習中のみなさん、一緒に続けていきましょう!
参考教材
この記事はUdemyの以下のコースを受講しながら学んだ内容を、自分の言葉でまとめたものです。
現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル(講師: 酒井潤)