Pythonロボティクスコース レッスン 6 *
テーマ.2-1 Pythonの制御の仕組み1
プログラムの2つの基本処理と複数の値をまとめてあつかうデータ型について学ぼう
チャプター1
このレッスンで学ぶこと
プログラムには「順次」「反復」「分岐」の3つの基本的な処理の流れがあります。このレッスンでは、その中の「順次」と「反復」の2つの処理について学びます。また、数値や文字列以外のデータ型についてもいくつか説明をします。レッスンの最後では、学習した基本処理と新しいデータ型を組み合わせて、あらかじめ登録した曲をブザーから流すための効率的なプログラムの作り方を紹介します。
チャプター2
Pythonのシーケンスなデータ
はじめに、「シーケンス(Sequence)」と呼ばれるデータについて学びます。シーケンスとは、複数の値を順番に並べ、それをひとつのかたまりとして扱うデータ型です。Pythonでは、以下のものがシーケンスとして用意されています。
- リスト ( list )
- タプル ( tuple )
- レンジ ( 標準関数の
range()
で取得できる数値の一覧 ) - 文字列 ( string ) ※実は文字列もシーケンスなデータの1種です。
次の2つは厳密に言うとシーケンスではありませんが、同じ系列で説明されることが多いデータ型です。
- 辞書 ( dict )
- 集合 ( set )
ここでは、「リスト」「タプル」「辞書」の3つのデータ型について詳しく見ていきます。
2. 1 リストについて
リストとは、複数の要素を一列に並べて格納するデータ型です。数値や文字列のデータをまとめて取り扱いたいときに、1つのオブジェクトとして管理できるためとても便利です。
■ リストの定義
リストは、以下のように角括弧 []
を使って作成します。
リスト名 = [ 要素0, 要素1, 要素2, ... ]
実際に、ターミナルで以下のコードを実行し、冷蔵庫にある食材を管理するリストfood
を作成しましょう。
>>> food = [‘milk’, ‘beef’, ‘egg’, ‘carrot’]
作成したリストの中身は、print()
を使うと確認できます。
>>> print(food)
[‘milk’, ‘beef’, ‘egg’, ‘carrot’]
■ リストの要素を取り出す
リストにある要素を取り出したいときは、[]
の中に要素の番号を書きます。
リスト名[番号]
リストに格納した要素は、先頭から順番に0番目、1番目、2番目… と0番目から数えます。日常生活のように1番目から数えるルールではないことに注意します。では、順番に番号を指定して、要素を取り出してみましょう。
>>> print(food[0])
milk
>>> print(food[1])
beef
>>> print(food[2])
egg
>>> print(food[3])
carrot
また、要素の番号として「-1」を指定すると、末尾の要素を取り出すことができます。
>>> print(food[-1])
carrot
■ リストの要素をまとめて取り出す
リストには スライス という複数の要素をまとめて取り出す方法があります。スライスには次のようなルールで記述します。
リスト名[ 開始位置 : 終了位置 ]
リストfood
の0番目から2番目の要素をスライスで取り出してみましょう。
>>> print(food[0:3])
[‘milk’, ‘beef’, ‘egg’]
上のコードでは、開始位置を0に、終了位置を3としています。実行結果から分かるように、終了位置に指定した番号の要素は取り出されません。つまり、「開始位置から終了位置 – 1」までの要素が取り出されることになります。
また、スライスでは増分を指定して要素を取り出すこともできます。
リスト名[ 開始位置 : 終了位置 : 増分 ]
増分を指定した場合、開始位置の要素から増分ずつ増えた番号の要素が終了位置まで順番に取り出されます。
[ 開始位置 ], [ 開始位置 + 増分×1 ], [ 開始位置 + 増分×2 ], ...
こちらも以下のコードを実行して確認しましょう。
>>> print(food[0:4:2])
[‘milk’, ‘egg’]
■ リストのメソッドを使う
リストはメソッドを使って要素を追加したり、削除したりすることもできます。
メソッド名 | 機能 |
---|---|
append() | リストの末尾に新しい要素を追加する |
pop() | 指定した番号の要素をリストから削除する |
remove() | 指定した値を持つ最初の要素をリストから削除する |
まずは、append()
メソッドを使って、冷蔵庫に新たに購入したベーコン'bacon'
を追加してみましょう。
>>> food.append(‘bacon’)
>>> print(food)
[‘milk’, ‘beef’, ‘egg’, ‘carrot’, ‘bacon’]
今度は、冷蔵庫から卵を使ったので、pop()
メソッドでリストから 'egg'
を削除してみましょう。'egg'
は2番目の要素なので、次のコードで削除できます。
>>> food.pop(2)
‘egg’
>>> print(food)
[‘milk’, ‘beef’, ‘carrot’, ‘bacon’]
food.pop(2)
を実行した後に、ターミナルに 'egg'
と表示されたのは、pop()
メソッドが戻り値としてリストから削除した要素を返すためです。要素が削除されたリストは再び0から番号が振り直されるため、次に2番目の要素を取り出すと carrot
と表示されます。
>>> print(food[2])
carrot
pop()
メソッドで特定の要素を削除するには、その要素の番号を覚えておかなくてはいけないため少し不便です。一方で、remove()
メソッドなら、要素の値を指定して削除することができます。
>>> food.remove(‘carrot’)
>>> print(food)
[‘milk’, ‘beef’, ‘bacon’]
pop()メソッド
と違い、remove()
メソッドには戻り値はありません。
2. 2 タプルについて
タプルは、リストとよく似たデータ型ですが、リストが要素を追加したり、削除したりするなど変更可能であるのに対して タプルは要素の変更ができません。リストのように変更可能であることを ミュータブル(mutable) 、タプルのように変更不可であることを イミュータブル(immutable) とも言います。つまり、タプルは一度作成すると、要素の上書きや追加、削除ができません。
これだけを見ると、タプルは使いどころが限られてしまい、「なぜタプルというものが存在するのか」と疑問に思うかもしれません。タプルがPythonで用意されている理由は、以下の2点にあると思ってください。
- リストよりも高速に動作する
一般的にプログラミングでは、便利に使える関数やメソッド、オブジェクトほど処理に時間がかかる傾向があります。タプルの方がリストよりも機能が少ない分、処理が高速になります。しかしながら、現在のコンピュータの性能を踏まえると、この差は実感しにくいかもしれません。 - 定数値として使える
変数や関数の名前を付けるときに、どういう目的で使うものかが分かるように名前を付けることが大切だと説明をしました。円周率や1日の時間の長さのように不変な値であっても、変数に格納して名前を付けることで、その値が何を表しているのかが把握しやすくなります。このように、プログラムの中で値が固定される変数のことを「定数」と言います。タプルも同じで、一連の固定された値をまとめて管理したいときに使います。
■ タプルの定義
タプルは丸括弧 ()
を使って、次のように作成します。
タプル名 = (要素1, 要素2, 要素3, ... )
例として、日本の関東地方の都道府県をタプルとしてまとめてみましょう。
>>> Kanto = (‘Ibaraki’, ‘Tochigi’, ‘Gunma’, ‘Saitama’, ‘Chiba’, ‘Tokyo’, ‘Kanagawa’)
タプルもリストと同じく、print()
関数で中身を確認できます。
>>> print(Kanto)
(‘Ibaraki’, ‘Tochigi’, ‘Gunma’, ‘Saitama’, ‘Chiba’, ‘Tokyo’, ‘Kanagawa’)
■ タプルの要素を取り出す
タプルもリストと同様に、0から始まる番号で要素が管理されています。そのため、要素を取り出すときも []
の中に番号を指定します。
>>> print(Kanto[2])
Gunma
タプルには、新しい要素を追加することはできませんが、タプルを格納する変数を上書きすることは可能です。
>>> a = (1, 2, 3)
>>> print(a)
(1, 2, 3)
>>> a = (4, 5, 6)
>>> print(a)
(4, 5, 6)
また、タプルに格納するデータが1つだけのときは注意が必要です。次のように記述すると、タプルとして扱われません。
>>> b = (1)
>>> print(b)
1
上記のように、b = (1)
という書き方だとb
は整数値 1
の変数になります。これはタプルが、四則演算でも使う 丸括弧()
を使っているためです。これを防ぐには、1
のあとに ,
を追加します。
>>> b = (1,)
>>> print(b)
(1,)
2. 3 辞書について
リストやタプルでは、各要素に0から順番に自動的に番号が振られ、その番号を指定することで要素を取り出すことができました。ここで紹介する 辞書 は、番号ではなく、ユーザーが自由に付けた「キー」で要素を管理することができます。
■ 辞書の定義
辞書は、以下ように波括弧{}
を使い、「 :(カンマ)」でキーと値をペアにして作成します。
辞書名 = { キー1: 要素1, キー2:要素2, キー3:要素3 ... }
キーは辞書の中で一意(同じものが2つ以上ない)でなければいけません。 同じキーで2つ以上の要素を登録しようとすると、後の要素で上書きされてしまいます。
例として、連絡先情報を管理する contact
という辞書を作り、名前 first_name
、名字 last_name
、電話番号 tel_no
という3つのキーに対して、それぞれにペアとなる値を登録してみましょう。
>>> contact = {‘first_name’:’Taro’, ‘last_name’:’Tanaka’, ‘tel_no’:’123-1234-0000′ }
>>> print(contact)
{‘tel_no’: ‘123-1234-0000’, ‘last_name’: ‘Tanaka’, ‘first_name’: ‘Taro’}
辞書は作成時に指定した順番で要素が管理されているわけではないため、print()
関数で表示した結果が必ずしも作成時の順番と一致しません。
■ 辞書の要素を取りだす
要素を取り出すときは、[]
内にキーを指定します。辞書という名前の通り、名前を調べて中身を検索しています。
辞書名[キー]
さきほど作成した辞書contact
の要素を取り出して表示してみましょう。
>>> print(contact[‘first_name’])
Taro
>>> print(contact[‘last_name’])
Tanaka
>>> print(contact[‘tel_no’])
123-1234-0000
辞書のキーは文字列以外にも、整数値やタプルを使うことができます。整数値の場合、リストと差がないように思えますが、リストと違い「2, 4, 6, …」のように、飛び飛びの整数値をキーとして使えるため、この方が都合が良い場合は辞書を使います。
■ 辞書に要素を追加する
辞書に新しい要素を追加するときはメソッドを使わず、次のように記述します。
辞書名[キー] = ペアとなる値
さきほどの辞書 contact
に新しく郵便番号を追加して、 print()
関数で表示してみましょう。
>>> contact[‘postcode’] = ‘111-1111’
>>> print(contact)
{‘first_name’: ‘Taro’, ‘postcode’: ‘111-1111’, ‘tel_no’: ‘123-1234-0000’, ‘last_name’: ‘Tanaka’}
■ 辞書のメソッドを使う
削除はリストと同様にpop()
メソッドを使います。では、先ほど追加した郵便番号を辞書から削除してみましょう。
>>> contact.pop(‘postcode’)
‘111-1111’
>>> print(contact)
{‘first_name’: ‘Taro’, ‘tel_no’: ‘123-1234-0000’, ‘last_name’: ‘Tanaka’}
辞書のpop()
メソッドも削除した要素を戻り値として返すようになっています。
チャプター3
順次処理
順次処理とは、命令を決めらた順番に実行していく処理です。Pythonでは上にある行から下の行へと順番にコードが実行されていきます。これまでのレッスンで作成してきたプログラムも、すべてこの順次処理が行われていました。
例)テーマ.1-4で作成したウエルカムボードのプログラム
チャプター4
反復処理
反復処理は、指定された範囲の命令を繰り返し行う処理です。繰り返しは大きく分けると、ずっと処理を繰り返す「永久ループ」と、ある条件を満たしている間は処理を繰り返す「条件付きループ」の2種類があります。どちらの反復処理もほとんどが while文 と for文 で記述されます。また、これらの反復処理を使うと、リストやタプルのようなシーケンスなデータの要素に対して順番に処理を行うプログラムを簡潔にまとめることもできます。
4. 1 while文を使った処理の反復
while文は、次のように記述します。これでwhile
の右に書いた条件式が成り立つ間だけ、内部のコードを繰り返し実行します。
while 条件式:
繰り返したい処理のコード
.
.
.
テーマ.1-3で関数を定義したときと同じように、while文の中のコードは先頭にインデント(空白文字)を付けて字下げします。また、条件式は、=
や >
、 <
の不等号を使って作成します。プログラムでは条件式におけるこれらの記号を 比較演算子 と呼びます。
条件式で使う比較演算子の例
比較演算子の記号 | 使い方 | 意味 |
---|---|---|
== | a == b | aとbが同じ |
!= | a != b | aとbは異なる |
< | a < b | aがbより小さい(a==bは含まない) |
> | a > b | aがbより大きい(a==bは含まない) |
<= | a <= b | aがb以下(a==bを含む) |
>= | a >= b | aがb以上(a==bを含む) |
比較演算子では、2つのデータが同じであるかどうかを比べるときに、=
ではなく、2つ重ねた ==
を使うことに注意してください。
■ 条件式を使った反復処理
では、例として0から9まで数字をカウントアップする処理をwhile文と比較演算子を使った条件式を組み合わせて作成します。以下のコードをエディタエリアに書きましょう。条件式のあとに「 :(コロン)」付け忘れないように注意してください。
【サンプルコード 4-1-1】
1.count = 0
2.while count < 10:
3. print(count)
4. count += 1
2行目のcount < 10
が条件式です。この条件式で変数count
が10より小さい間は内部のコードを繰り返すようになっています。また、4行目のcount += 1
はcount = count + 1
と同じ処理を表し、繰り返すたびに変数count
が1ずつ増加するようになっています。反対に1ずつ減らしたい場合は、count = count - 1
の代わりに、count -= 1
と省略して書くことができます。
このプログラムを実行して、次のようにターミナルに0から9まで順番に数字が表示されることを確認しましょう。
0
1
2
3
4
5
6
7
8
9
4. 2 for文を使った処理の反復
for文はリストやタプル、ここで新しく紹介する関数「 range()
」と組み合わせて使用します。例えば、先ほどのカウントアップのプログラムをfor文で書き直すと次のようになります。
【サンプルコード 4-2-1】
1.for count in range(10):
2. print(count)
このプログラムを実行して、while文を使った場合と同じ結果が出力されることを確認しましょう。
初めて出てくるin
演算子や range()
関数があるため、このプログラムが難しく感じるかもしれません。ですが、1つ1つの役割を確認していくと、それほど難しくないことがすぐに分かります。
■ range()関数の役割
range()
関数は引数に指定した条件で整数の並びを生成します。このrange()
関数には次の3つの引数があります。
range(始まりの整数値, 終わりの整数値, 増加量)
生成されるのは、「始まりの整数値」から「終わりの整数値」まで「増加量」分ずつ増えていく整数の並びです。「始まりの整数値」と「増加量」の2つの引数は省略することができ、省略した場合は始まりの数値が「0」、増加量が「1」となります。「終わりの整数値」は、生成された整数の並びには含まれないため、増加量が1の場合は「始まりの整数値 ~ 終わり整数値 – 1」の並びとなります。
range()
関数で生成される整数値の並びは、リストでもタプルでもありません。「イテレータ」と呼ばれる特殊なオブジェクトとして扱われます。実際にターミナルで次のコードを実行すると、戻り値がリストやタプルではないことが分かります。
>>> range(10)
range(0, 10)
■ in演算子の役割
for文の中で、in
演算子は、リストやタプル、辞書、レンジ(range)から要素をひとつずつ取り出す働きをします。そのため、for count in range(10):
と書くと、range(10)
で生成された0から9の整数の並びから、順番に数字を取り出すことができます。
他にもin
演算子は、特定の値を持つ要素がリストやタプル、辞書の中に存在するかどうかを確かめるためにも使われます。
以上のことを踏まえて、もう一度【サンプルコード 4-2-1】を確認してみましょう。
1.for count in range(10):
2. print(count)
つまり、range(10)
によって生成された「0~9」の整数の並びから、in
演算子で順番に数字を取り出し、変数count
に格納して、内部のコードを繰り返し実行しているということになります。
今はまだ少し疑問が残っているかもしれませんが、range()
関数の振る舞いを理解できると、反対に9から0までカウントダウンするプログラムも簡単に作成することができます。
【サンプルコード 4-2-2】
1.for count in range(9, -1, -1):
2. print(count)
(実行結果)
9
8
7
6
5
4
3
2
1
0
増加量に負の整数を指定すると、「9, 8, 7, 6, …」のように逆順で整数の並びが作成でき、このようなカウントダウンの処理が行われるようになります。
4. 3 リストやタプルを利用した処理の反復
上でも少し触れましたが、for文でin
演算子を使うとリストやタプル、辞書の要素を順番に取り出すこともできます。
■ リストの要素を順番に取り出す
次の例では、作成した果物の価格のリストfruits
から順番に要素を取り出して変数fruit
に格納し、print()
関数でターミナルに出力しています。
【サンプルコード 4-3-1】
1.fruits = [‘apple’, ‘banana’, ‘cherry’, ‘orange’]
2.for fruit in fruits:
3. print(fruit)
(実行結果)
apple
banana
cherry
orange
■ タプルの要素を順番に取り出す
タプルもリストと同じ方法で順番に要素を取り出せます。そのため、上のプログラムで定義した果物のリストfruits
をタプルに変えても同じ実行結果となります。
【サンプルコード 4-3-2】
1.fruits = (‘apple’, ‘banana’, ‘cherry’, ‘orange’)
2.for fruit in fruits:
3. print(fruit)
(実行結果)
apple
banana
cherry
orange
■ 辞書の要素を順番に取り出す
辞書の場合は、リストやタプルと同じように書くと、要素ではなくキーが取り出されます。ただし辞書では、登録した順番と取り出される順番が一致しないことに注意してください。
【サンプルコード 4-3-3】
- fruits = {‘apple’:120, ‘banana’:80, ‘cherry’:300, ‘orange’:100}
- for key in fruits:
- print(key)
(実行結果)
orange apple banana cherry
そのため、値を取り出したい場合はvalues()
メソッドを使い、次のように書きます。
【サンプルコード 4-3-4】
- fruits = {‘apple’:120, ‘banana’:80, ‘cherry’:300, ‘orange’:100}
- for value in fruits.values():
- print(value)
(実行結果)
100 120 80 300
また、キーと値の両方を取り出したい場合はitems()
メソッドを使います。このとき、キーと値はタプルとして取り出されます。
【サンプルコード 4-3-5】
- fruits = {‘apple’:120, ‘banana’:80, ‘cherry’:300, ‘orange’:100}
- for item in fruits.items():
- print(item)
(実行結果)
(‘orange’, 100) (‘apple’, 120) (‘banana’, 80) (‘cherry’, 300)
チャプター5
課題:タプルを使った曲データの作成
最後に、このレッスンで学習したタプルとfor文を組み合わせて、Studuino:bitのブザーから曲を流すプログラムを簡潔にまとめてみましょう。
5. 1 プログラムの作成
まず、Studuino:bitのブザーを使う準備をします。下のコードをコピーしてエディタエリアに貼りつけましょう。
- from pystubit.board import buzzer
- import time
次に、曲のデータをタプルにまとめます。1曲の中には複数の音の情報が含まれおり、さらに音の情報は音階と長さの組み合わせで表すことができます。そこで、タプルの中に別のタプルを入れた2重構造として曲を用意します。
今回用意する曲は、「C4」のドから1オクターブ高い「C5」のドまで順番に音を鳴らす簡単なものにしておきましょう。
番号 | 音階 | 長さ |
---|---|---|
0 | C4(ド) | 600 |
1 | D4(レ) | 600 |
2 | E4(ミ) | 600 |
3 | F4(ファ) | 600 |
4 | G4(ソ) | 600 |
5 | A4(ラ) | 600 |
6 | B4(シ) | 600 |
7 | C5(ド) | 600 |
上の曲をタプルで作成したのが以下のコードになります。タプルやリスト、辞書を作成するときは、このように改行して要素を1行に1つずつ書いていくことができます。行数は多くなりますが、見通しが良くなるため、1行が長くなる場合はこの形式で書くことをお勧めします。
- from pystubit.board import buzzer
- import time
- music = (
- (‘C4’, 600),
- (‘D4’, 600),
- (‘E4’, 600),
- (‘F4’, 600),
- (‘G4’, 600),
- (‘A4’, 600),
- (‘B4’, 600),
- (‘C5’, 600),
- )
定義したタプルから、for文で順番に要素を取り出します。以下のコードでは、変数 tone
に要素を格納し、さらにtone[0]
で音階を、tone[1]
で長さをそれぞれ取り出しています。
【サンプルコード 5-1-1】
- from pystubit.board import buzzer
- import time
- music = (
- (‘C4’, 600),
- (‘D4’, 600),
- (‘E4’, 600),
- (‘F4’, 600),
- (‘G4’, 600),
- (‘A4’, 600),
- (‘B4’, 600),
- (‘C5’, 600),
- )
- for tone in music:
- buzzer.on(tone[0])
- time.sleep_ms(tone[1])
- buzzer.off()
18行目はインデントがないことに気を付けてください。完成したプログラムを実行して、動作を確認しましょう。
5. 2 タプルとfor文を使わなかったときとの行数の比較
上の【サンプルコード 5-1-1】を詰めて書くと、以下のように7行のプログラムになっています。
【サンプルコード 5-2-1】
- from pystubit.board import buzzer
- import time
- music = ((‘C4’,600),(‘D4’,600),(‘E4’,600),(‘F4’,600),(‘G4’,600),(‘A4’,600),(‘B4’,600),(‘C5’,600),)
- for tone in music:
- buzzer.on(tone[0])
- time.sleep_ms(tone[1])
- buzzer.off()
このプログラムをタプルとfor文を使わずに書くと、以下のように19行のプログラムになります。この違いからも、for文を使うことでプログラムが簡潔にまめられていることが分かります。
【サンプルコード 5-2-2】
- from pystubit.board import buzzer
- import time
- buzzer.on(‘C4’)
- time.sleep_ms(600)
- buzzer.on(‘D4’)
- time.sleep_ms(600)
- buzzer.on(‘E4’)
- time.sleep_ms(600)
- buzzer.on(‘F4’)
- time.sleep_ms(600)
- buzzer.on(‘G4’)
- time.sleep_ms(600)
- buzzer.on(‘A4’)
- time.sleep_ms(600)
- buzzer.on(‘B4’)
- time.sleep_ms(600)
- buzzer.on(‘C5’)
- time.sleep_ms(600)
- buzzer.off()
チャプター6
おわりに
6. 1 このレッスンのまとめ
このレッスンではリスト、タプルといったシーケンスなデータ型について学習しました。また、while文とfor文を使用した反復処理によって、プログラムを簡潔にまとめる方法についても見てきました。これらはどれも、これから多くのプログラムを書いていく際の最も基礎的な構文となります。自分の理解度に不安がある場合は、始めからもう一度見直しておきましょう。
6. 2 次回のレッスンについて
次回のレッスンでは、もうひとつのプログラムの基本となる処理の「分岐」について学びます。
チャプターを全部クリアしよう!