Python速習ガイド - ステップ1 基本的な文法とデータ型 (6) - リスト (2)
シリーズ - Python速習ガイド
コンテンツ
Info
- 本講座は、Pythonプログラミングの基礎を手を動かしながら最速で身につけるための講座です。
- 「スタイルガイド」では、Pythonできれいなコードを書くためのガイドライン(PEP8)で紹介されている内容を主に記載しています。
- 各コードは実行して結果を確認することができます。
ページの再読み込みで元の内容に戻りますので、自由にいじってみてください。
「ステップ1 基本的な文法とデータ型」の続きです。
1.5. データをまとめる
1.5.1. リスト
リストの操作
存在チェック(in
, not in
)
- ある要素がリスト内に存在するかどうかを確認するためには、
in
演算子を使用します。
not in
演算子を使用すると、in
演算子と逆の判定を行います。
スライス
[開始位置:終了位置]
のように範囲を指定して、リストの一部分を取得することができます。- このようにして取得できるリストの一部分のことを スライス といいます。
- この場合、
開始位置
以上終了位置
未満 (開始位置 <= x < 終了位置
)の要素からなるスライスとなり、
終了位置
で指定したインデックスの要素は 含まれない ことに注意してください。
- 指定した範囲が実際のリストの範囲を超えている場合、
エラーは発生せずに、指定範囲のうち実際の範囲内のスライスを返します。- 指定した範囲に値が1つも存在しない場合、空のリスト(
[]
)を返します。 - スライスの場合、範囲外のインデックスを指定しても
IndexError
は発生しません。
- 指定した範囲に値が1つも存在しない場合、空のリスト(
- 「開始位置」を省略した場合(
[:終了位置]
)、先頭からのスライスとなります。 - 「終了位置」を省略した場合(
[開始位置:]
)、末尾までのスライスとなります。
[開始位置:終了位置:ステップ数]
のように指定すると、ステップ数で指定した個数飛びのスライスを取得します。
- 「ステップ数」にマイナスの数を指定すると、逆順のスライスを取得できます。
- 後ろから逆順に進むため、
開始位置
以下終了位置
超 (開始位置 >= x > 終了位置
)
の範囲のスライスとなります。終了位置
の要素はスライスに含みません。
- 後ろから逆順に進むため、
- マイナスのステップ数の場合、
開始位置
を空にすると、末尾からのスライスとなります。終了位置
を空にすると、先頭までのスライスとなります。
📚練習問題
1~20を要素とするリストを使用して、以下を実施しましょう。
- 5~15の数からなるスライスを出力しましょう。
- 5の倍数のスライスを出力しましょう。
- 3の倍数の逆順のスライスを出力しましょう。
スライスによる書き換え
- スライスを使用してリストの要素を書き換えることができます。
- サイズの異なるリストの代入もエラーが発生せずできてしまうため、注意してください。
リストのコピー
「1.4. 変数と代入」にて、変数は「ラベル」のようなものであると説明しました。
ここで、Pythonでよくある間違いを紹介して、変数が「ラベル」であることを示します。
上記コードを実行すると分かる通り、元の価格リスト(original_prices
)も変化してしまっています。
この理由は、変数が「ラベル」であることを意識すると理解できます。
graph TD subgraph "ステップ3: 要素の変更" list3["[500, 1500, 5000]"] original_prices3[original_prices] --> list3 new_prices3[new_prices] --> list3 end subgraph "ステップ2: 新しい変数に代入" list2["[1000, 1500, 5000]"] original_prices2[original_prices] --> list2 new_prices2[new_prices] --> list2 end subgraph "ステップ1: 初期状態" list1["[1000, 1500, 5000]"] original_prices1[original_prices] --> list1 end style list1 fill:#fff3bf,stroke:#333,stroke-width:2px style list2 fill:#fff3bf,stroke:#333,stroke-width:2px style list3 fill:#fff3bf,stroke:#ff0000,stroke-width:2px
このように、Pythonでは変数を新しい変数に代入した場合、
新しい変数にデータが移るのではなく、新しい変数も元のデータを指し示すラベルとなります。
(つまり、最初の変数も新しい変数もどちらも同じ元データを参照します。)
- リストをコピーするには、
copy()
メソッドを使用します。
graph TB %% ステップ1: 初期状態 subgraph step1["ステップ1: 初期状態"] direction TB op1[original_prices] --> list1["[1000, 1500, 5000]"] end step1 --> step2 %% ステップ2: copy()メソッド実行後 subgraph step2["ステップ2: copy()メソッドを使ってリストをコピー"] direction TB op2[original_prices] --> list2["[1000, 1500, 5000]"] list2 -. "copy()" .-> list2_copy["[1000, 1500, 5000] (コピー)"] np2[new_prices] --> list2_copy end step2 --> step3 %% ステップ3: 変更後 subgraph step3["ステップ3: 新しいリスト側の要素を変更後"] direction TB op3[original_prices] --> list3["[1000, 1500, 5000]"] np3[new_prices] --> list3_copy["[500, 1500, 5000]"] end %% スタイル設定 style list1 fill:#fff3bf,stroke:#333,stroke-width:2px style list2 fill:#fff3bf,stroke:#333,stroke-width:2px style list3 fill:#fff3bf,stroke:#333,stroke-width:2px style list2_copy fill:#fff3bf,stroke:#333,stroke-width:2px style list3_copy fill:#fff3bf,stroke:#ff0000,stroke-width:2px linkStyle 3 stroke:#4285F4,stroke-width:2px
- 開始位置と終了位置を省略したスライス
[:]
でも同様にコピーすることができます。
しかし、copy()
メソッドやスライス [:]
でも問題が生じる場合があります。
以下でその例を紹介します:
これは、copy()
メソッドやスライス[:]
では、外側のリスト([..., ..., ...]
)は複製されても
内側の値(["apple", 120]
など)は複製されず、元のリストと同じ値を参照してしまうためです。
このようなコピーのことを「浅いコピー (シャローコピー)」といいます。
graph TB %% ステップ1: 初期状態 subgraph step1["ステップ1: 初期状態"] direction TB np1[name_and_prices] --> outer1["[..., ..., ...]"] outer1 --> apple1["['apple', 120]"] outer1 --> orange1["['orange', 150]"] outer1 --> grape1["['grape', 180]"] end step1 --> step2 %% ステップ2: copy()メソッド実行後 subgraph step2["ステップ2: copy()メソッドを使ってリストをコピー"] direction TB np2[name_and_prices] --> outer2["[..., ..., ...]"] nnp2[new_name_and_prices] --> outer2_copy["[..., ..., ...] (コピー)"] outer2 --> apple2["['apple', 120]"] outer2 --> orange2["['orange', 150]"] outer2 --> grape2["['grape', 180]"] outer2_copy --> apple2 outer2_copy --> orange2 outer2_copy --> grape2 end step2 --> step3 %% ステップ3: 変更後 subgraph step3["ステップ3: 新しいリスト内の要素(リスト)の要素を変更後"] direction TB np3[name_and_prices] --> outer3["[..., ..., ...]"] nnp3[new_name_and_prices] --> outer3_copy["[..., ..., ...] (コピー)"] outer3 --> apple3["['apple', 120]"] outer3 --> orange3["['orange', 200]"] outer3 --> grape3["['grape', 180]"] outer3_copy --> apple3 outer3_copy --> orange3 outer3_copy --> grape3 end %% スタイル設定 style outer1 fill:#fff3bf,stroke:#333,stroke-width:2px style outer2 fill:#fff3bf,stroke:#333,stroke-width:2px style outer3 fill:#fff3bf,stroke:#333,stroke-width:2px style outer2_copy fill:#fff3bf,stroke:#333,stroke-width:2px style outer3_copy fill:#fff3bf,stroke:#333,stroke-width:2px style apple1 fill:#ffc078,stroke:#333,stroke-width:2px style orange1 fill:#ffc078,stroke:#333,stroke-width:2px style grape1 fill:#ffc078,stroke:#333,stroke-width:2px style apple2 fill:#ffc078,stroke:#333,stroke-width:2px style orange2 fill:#ffc078,stroke:#333,stroke-width:2px style grape2 fill:#ffc078,stroke:#333,stroke-width:2px style apple3 fill:#ffc078,stroke:#333,stroke-width:2px style orange3 fill:#ffc078,stroke:#ff0000,stroke-width:2px style grape3 fill:#ffc078,stroke:#333,stroke-width:2px
- 要素(リスト)内の要素を変更するのではなく、要素自体を(丸ごと)入れ替える場合は、
「1.4.3. 変数への再代入」で説明した「ラベルの付け替え」操作となるため、元のリストには影響を与えません。
graph TB %% ステップ1: 初期状態 subgraph step1["ステップ1: 初期状態"] direction TB np1[name_and_prices] --> outer1["[..., ..., ...]"] outer1 --> apple1["['apple', 120]"] outer1 --> orange1["['orange', 150]"] outer1 --> grape1["['grape', 180]"] end step1 --> step2 %% ステップ2: copy()メソッド実行後 subgraph step2["ステップ2: copy()メソッドを使ってリストをコピー"] direction TB np2[name_and_prices] --> outer2["[..., ..., ...]"] nnp2[new_name_and_prices] --> outer2_copy["[..., ..., ...] (コピー)"] outer2 --> apple2["['apple', 120]"] outer2 --> orange2["['orange', 150]"] outer2 --> grape2["['grape', 180]"] outer2_copy --> apple2 outer2_copy --> orange2 outer2_copy --> grape2 end step2 --> step3 %% ステップ3: 要素丸ごと入れ替え後 subgraph step3["ステップ3: 新しいリストの1要素を丸ごと入れ替え後"] direction TB np3[name_and_prices] --> outer3["[..., ..., ...]"] nnp3[new_name_and_prices] --> outer3_copy["[..., ..., ...] (コピー)"] outer3 --> apple3["['apple', 120]"] outer3 --> orange3["['orange', 150]"] outer3 --> grape3["['grape', 180]"] outer3_copy --> apple3 outer3_copy --> orange3 outer3_copy -. "置き換え前" .-> grape3 outer3_copy -- "置き換え後" --> banana3["['banana', 200]"] end %% スタイル設定 style outer1 fill:#fff3bf,stroke:#333,stroke-width:2px style outer2 fill:#fff3bf,stroke:#333,stroke-width:2px style outer3 fill:#fff3bf,stroke:#333,stroke-width:2px style outer2_copy fill:#fff3bf,stroke:#333,stroke-width:2px style outer3_copy fill:#fff3bf,stroke:#333,stroke-width:2px style apple1 fill:#ffc078,stroke:#333,stroke-width:2px style orange1 fill:#ffc078,stroke:#333,stroke-width:2px style grape1 fill:#ffc078,stroke:#333,stroke-width:2px style apple2 fill:#ffc078,stroke:#333,stroke-width:2px style orange2 fill:#ffc078,stroke:#333,stroke-width:2px style grape2 fill:#ffc078,stroke:#333,stroke-width:2px style apple3 fill:#ffc078,stroke:#333,stroke-width:2px style orange3 fill:#ffc078,stroke:#333,stroke-width:2px style grape3 fill:#ffc078,stroke:#333,stroke-width:2px style banana3 fill:#ffc078,stroke:#ff0000,stroke-width:2px
📚練習問題
上記コードにて、copy()
メソッドでコピーせずに実施した場合にどうなるか考えてみましょう。
浅いコピーと深いコピー
上記の浅いコピー(シャローコピー)に対して、その要素や要素の要素などすべて含めて、
完全に複製するコピーのことを「深いコピー (ディープコピー)」といいます。
深いコピーはcopy
ライブラリのdeepcopy
関数を用いて、以下のようにして実施できます:
(「ライブラリ」については、詳しくは後ほど解説します)
アンパック
- リストの要素をそれぞれ別の変数に代入したい場合、イコール(
=
)の左側に変数をカンマ(,
)区切りで書くことで代入できます。- この操作のことを アンパック (unpack) といいます。
- 変数の数と代入値の要素数が異なる場合、
ValueError
が発生します。
- アンパック演算子
*
を使うと、「最初の要素」と「その他」で分けるようなアンパックが可能です。
(掛け算で使われる2項演算子の*
とは異なり、変数の頭に*
をつけます。)
- 複数のアンパック演算子
*
を使ったアンパックはSyntaxError
(構文エラー)が発生します。
- アンパックで使わない値はアンダースコア (
_
) で受け取ることができます。- これはその値を使わないということを明示するためのPythonでの慣習です。
bool
関数による型変換
- リストに
bool
関数を適用すると、空のリスト([]
)の場合にFalse
、それ以外にTrue
を返します。