応用プログラミング及び実習 2019年度 第4回 Notebook

Python プログラミングの初歩 (4)

この資料中に説明なくページ番号が出てくる場合,教科書のページ番号を表しています.

前回の復習+α

復習として,次の問題をやってみましょう: 「以下の2つのセルのうち下の方のセルを実行するとリストdataの最大値が正しく出力されるように,上の方のセルに関数を定義しなさい」

In [ ]:
# このセルに関数の定義を書く
In [ ]:
# 上記の関数を呼ぶ(このセルの内容は変更不可)
data = [ -5, -9, -6, -3, -4, -6, -4, -9 ]
val = mymax(data)
print("最大値は", val, "です")

以下の2つのセルについても同様に考えてやってみましょう.

In [ ]:
# このセルに関数の定義を書く
In [ ]:
# 上記の関数を呼ぶ(このセルの内容は変更不可)
i = myargmax(data)
print("最大値は", data[i], "です")

ディクショナリ(辞書)を使う (pp.114-123)

ディクショナリとは (pp.114-117)

以前学んだ リスト は,複数の要素を順番付きでひとまとめにして扱うものである. 個々の要素をばらばらに扱うのに比べて,簡潔なプログラムを書くことができる.

In [ ]:
# 10個の数の和(1)
x01 = 1; x02 = 2; x03 = 3; x04 = 4; x05 = 5; x06 = 6; x07 = 7; x08 = 8; x09 = 9; x10 = 10     #  ;(セミコロン)使うと複数行を1行に書ける
print(x01 + x02 + x03 + x04 + x05 + x06 + x07 + x08 + x09 + x10)
In [ ]:
# 10個の数の和(2)
L = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
s = 0
for item in L:
    s += item
print(s)
In [ ]:
# 10個の数の和(3)
print(sum(L))

リストの場合,「生徒の点数」,「生徒の氏名」のように同じ種類のデータを複数まとめて扱うことが多い(もちろん異なる種類のデータを並べることもできるが).一方で,例えばある人の「ニックネーム」,「キャッチフレーズ」,「出身地」のように性質の異なる情報をひとまとめにして扱いたい,という場合もあるだろう.

そういう場合,Python では ディクショナリ辞書)というものを使うとよい.例えば,上記の「ニックネーム」,「キャッチフレーズ」,「出身地」という3つの情報まとめたディクショナリは,次のように定義することができる.

In [ ]:
purple = { "ニックネーム": "れにちゃん", "出身地": "神奈川県", "キャッチフレーズ": "感電少女" }

ディクショナリの定義は

{ キー1: 値1, キー2: 値2, ... }

のように, キー とそれに対応した値を :(コロン)の前後に並べて書く.この例では,purple という変数が表すディクショナリには ニックネーム出身地キャッチフレーズ という3種類のキーがあり,れにちゃん神奈川県感電少女 というのがそれぞれのキーに対応した値ということになる.

もう一つ定義してみよう.この例の変数 hoge も上記の purple と同じキーを持っているが,値は異なっている.

In [ ]:
hoge = { "ニックネーム": "ほげお", "出身地": "滋賀県", "キャッチフレーズ": "ほげほげ〜" }

Notebook や IPython 上では,ディクショナリを表す変数を書いたセルを実行すると,その内容を確認できる.

In [ ]:
purple

プログラム等の中では,print()関数を使って表示させることができる.

In [ ]:
print(purple)

ディクショナリの中身全部ではなく,特定のキーに対応した値のみを知りたい場合,

ディクショナリを表す変数名[ キー ]

という形を使う.

In [ ]:
purple["ニックネーム"]
In [ ]:
purple["出身地"]
In [ ]:
print(purple["出身地"])
In [ ]:
hoge["キャッチフレーズ"]

値の変更,追加,削除 (pp.117-120)

キーとして存在しないものを指定すると,どうなるだろう?

In [ ]:
hoge["防御力"]

このように,KeyError というエラーになる.

次のように代入文を使うと,指定したキーに対応した値を変更できる

ディクショナリを表す変数名[ キー ] = なんたら
In [ ]:
purple["キャッチフレーズ"] = "鋼少女"
purple

代入文で指定したキーが存在しなかった場合,新しい要素を追加することになる

In [ ]:
purple["生年月日"] = "1993年6月21日"
purple
In [ ]:
# このセルに, ディクショナリ hoge にキーが "防御力" で値が整数値 1 となる要素を追加するコードを書きなさい
In [ ]:
hoge

上記のように,値としては文字列に限らず任意のものを代入することができる(この例では整数値).

del文を使って要素を削除することもできる

In [ ]:
del purple["ニックネーム"]
purple

検索 (pp.120-123)

リストで使った in演算子(p.86)を使うと,ディクショナリ中に指定したキーが存在するかどうかを調べることができる.

In [ ]:
"キャッチフレーズ" in purple
In [ ]:
key = "キャッチフレーズ"
if key in purple:
    print(purple[key])
In [ ]:
"防御力" in purple
In [ ]:
key = "防御力"
if key in purple:
    print(purple[key])

以下は,p.122の例.

In [ ]:
# アラビア数字をローマ数字に変換する
#
def convert_number(num):
    # アラビア数字とローマ数字の対応表をディクショナリに定義
    roman_nums = {1:"I", 2:"II", 3:"III", 4:"IV", 5:"V", 6:"VI", 7:"VII", 8:"VIII", 9:"IX"}
    if num in roman_nums:
        # ディクショナリのキーとして引数の整数が存在していたら
        # キーに対応する値を戻り値にする
        return roman_nums[num]
    else:
        return "[変換できません]"
In [ ]:
print(convert_number(9))
In [ ]:
print(convert_number(0))

リストをシーケンスとして for文にわたすと,その要素を先頭から順に取り出して繰り返し処理を行うことができる.

In [ ]:
L = [ 0, "位置", "荷", 3.1415, ["し", "よん"], 5 ]
for item in L:
    print(item)

ディクショナリをシーケンスとして for文にわたすと,そのキーを取り出して繰り返し処理を行うことができる.

In [ ]:
purple = {"ニックネーム": "れにちゃん",
          "出身地": "神奈川県",
          "キャッチフレーズ": "感電少女",
          "生年月日": "1993年6月21日"}
for key in purple:
    print(key)
In [ ]:
for key in purple:
    print(key + ": " + purple[key])

(よだんだよん) 上記の例を龍大計算機室の環境で実行すると,辞書を定義したときのキーの並び順と出力結果のキーの並び順が同じになっていることが分かるだろう. Python ではバージョン 3.6 でディクショナリの扱いに変更が加えられ,定義した時のキーの順序を保存するようになったが,以前はそのような保証はなかった(p.117参照). 互換性に気を配って古い環境でも動くようにしたい場合,辞書のキーが定義した順に取り出されるとは限らない前提でプログラムを書かないといけない. ちなみに,いま実行している Python のバージョンは次のセルを実行すれば確認できる.

In [ ]:
import sys
sys.version

タプルを使う (pp.130-135)

「set(集合)を使う(pp.123-130)」はスキップします

これまで学んできた リストディクショナリ は,「複数のデータを組にして扱う」ための データ構造 (コンピュータ上でデータを扱いやすくするために用意された仕組み)を Python で実現したものです. ここで扱う タプル (tuple) もまた, 「複数のデータを組にして扱う」ための仕組みです.

リストは複数の値を [] で囲んで定義しましたが,タプルの場合は () で囲んで定義します.

In [ ]:
# タプルの定義
month_names = ("January", "February", "March", "April", "May", "June", "July")

それ以外の書き方や性質はリストによく似ています.

In [ ]:
# 要素番号を指定して要素を取り出す
month_names[1]
In [ ]:
# + 演算子を使って二つのタプルを連結する
month_names = month_names + ("August", "September", "October",  "November", "December")
month_names
In [ ]:
month_names[9]

組み込み関数len()で要素数を取得したり,in演算子で要素を検索したりもできます.

In [ ]:
len(month_names)
In [ ]:
for key in [ "October", "10月", "神無月" ]:
    print("\"" + key + "\"はこのタプルの要素", end = "")
    if key in month_names:
        print("です")
    else:
        print("ではありません")

リストとタプルの最大の違いは,タプルは要素の変更ができないというところです. 以下はエラーになります.

In [ ]:
# 0番目の要素を変更しようとしてみる
month_names[0] = "睦月"

del を使って要素を削除しようとしても同様にエラーになります.

「そんな性質何がうれしいの?」と思われるかもしれません.この授業ではこれ以上深入りしませんが,この「要素を変更できない」という性質が必要な場面は結構あるのです.タプルはそういう場面で活躍します(詳しくはpp.132-135).

最後に,要素が1つだけのタプルに関する注意.

In [ ]:
# 要素が1つだけのリスト
list1 = ["ぼっち"]
list1

リストの場合,要素数 1 のリストは,上記のように単に [, ] で囲めば定義できます. しかし,タプルの場合,(, ) で囲んだだけではうまくいきません

In [ ]:
# 要素が1つだけのタプル(として正しく定義できてない)
tuple1 = ("ぼっち")
tuple1

上記の場合,括弧はタプルを表す記号ではなく演算順序を表すためにつける記号と解釈されてしまうので,タプルになっていません. p.132 を参考に,tuple1が要素数1のタプルとなるよう上記セルの内容を修正しなさい.

右側に要素がならんでない , はなんだか寂しい...ぼっち感...

論理演算 (pp.135-138)

以前学んだ if 文の話のつづき. if文などの条件式には,以下の例のように,演算結果が True(真) か False(偽) のいずれかになるような式を書くのでした.

In [ ]:
4649 + 1314 == 5963
In [ ]:
"Hoge" == "hoge"

教科書 p.136 に,このような式で使うことのできる演算子がいくつか紹介されています. そちらも参考に,以下のセルを実行した結果がそれぞれどうなるか予想しながら実行してみましょう.

In [ ]:
5**(4-4)+9 == 10
In [ ]:
5 > 2
In [ ]:
100 == 100.0
In [ ]:
"かなこ" != "かなこぉ↑↑"
In [ ]:
[1, 2, 3] == [1, 2, 3]
In [ ]:
"ほげ" in "ホゲとかHOGEとかHogeとか,もううんざりだほげ"
In [ ]:
"ほげ" in [ "ホゲ", "HOGE", "Hoge", "ほげ"]
In [ ]:
4949 in [ 1818, 2929, 4848, 5959 ]

文字列に対して <>= といった比較演算子を使うと...

In [ ]:
"a" < "b"
In [ ]:
"a" > "b"
In [ ]:
"ab" < "b"
In [ ]:
"abc" < "ab"
In [ ]:
"this" < "that"

このように,辞書式順序(一般的な辞書で使われるような順序)で大小関係が決まります. ただし,「文字コード」に基づいて計算される順序ですので,数字や記号を含んだり,日本語文だったりする場合には,直感に反する結果や謎な結果となりますので,注意が必要です.

In [ ]:
"ほげ" < "Hoge"
In [ ]:
"10" < "9"

上記の最後の例は,謎でも何でもなく,文字列として辞書式順序で比較しているのですから当然の結果ですね. 整数として比較させたければ, int() 使って変換する等しないといけません.

C言語でint型の変数xに格納された値が「0以上でありかつ100以下である」というような判定をしたい場合,次のような条件式を書きました.

0 <= x && x <= 100

この式で使っている演算子 && は,「かつ」を意味するものでした.「または」の時は || でした.

Python にも,このように複数の条件式を組み合わせる時に使う 論理演算子 があります. ここでは,そのうち andornot の3つを紹介します.

In [ ]:
x = 60
if 0 <= x and x <= 100:
    print("0以上かつ100以下です")
if 0 <= x or x <= 100:
    print("0以上または100以下です")
if not x <= 100:
    print("100以下ではありません")
    
if not ((not 0 <= x) or (not x <= 100)):   # (よだんだよん) ド・モルガンの法則  
    print("ほげ")

上記の x の値をいろいろ変えて動作確認しましょう.

not は,in と組み合わせて次のように使うこともできます."HOGE"見つからなかったら True になります.

In [ ]:
"HOGE" not in "GEHOGOHO"

ところで,C言語を学び始めたばかりの頃,xが「0以上でありかつ100以下である」を次のように書いて失敗した経験はありませんか?

0 <= x <= 100

実は Python ではこの書き方が通ってしまいます.

In [ ]:
x = 60
0 <= x <= 100

x の値をいろいろ変えて動作確認すると予想がつく通り,and でつながってると解釈されます.

チェック

TAさんに課題Aのチェックを受ける際は,以下のセルを実行して「OK!」が出ているようにしてください.

In [ ]:
# 以下のコードは,この notebook を(それなりに)ちゃんと実行したかどうか確認するためのものです.
# 中身の理解は不要です.

fnpy = '/roes/sample/takataka/aprog/aprogCheck.py'
import os
if not os.path.isfile(fnpy):
    print('この環境では確認できないようです')
else:
    import sys
    sys.path.append('/roes/sample/takataka/aprog/')
    import aprogCheck
    aprogCheck.check('04note', In)
In [ ]: