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

Python の基礎 (1)

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

前回の復習+α

ディクショナリ(辞書)の話を復習しよう.以下の内容は,前回の課題B-1そのままです.

以下のセルを修正して,変数 hoge が次のようなキーと値のペアを持つディクショナリとなるようにしなさい.

キー
名前 "ほげお"
HP 18
MP 999
In [ ]:
# ディクショナリ hoge を定義する

★ 次の指示にしたがって hoge の内容を変更しなさい.

  1. キー MP の値 999 は間違いで,本当は 0 だった.修正しよう
  2. キー 攻撃力0.1 を追加
  3. キー 防御力0.001 を追加
In [ ]:
# ここに hoge の内容を変更する処理を書く

print(hoge)

★ 以下の関数を,次の実行例のような結果が得られるように修正しなさい

<実行例>
Wizard(hoge)
ほげお は魔法使えません
In [ ]:
# 魔法使い判定関数   MP が 0 より大きければ「魔法使い」
#
def Wizard(p):
    if p > 0:                                        # この行修正必要
        print(p, "は魔法使いです")      # この行修正必要
    else:
        print(p, "は魔法使えません")   # この行修正必要
In [ ]:
Wizard(hoge)

以下を実行すると変な出力が得られる.

In [ ]:
for k in [ "攻撃力", "防御力", "すばやさ"]:
        print(hoge["名前"], "の", k, "は", k, "です")

★ これを修正して,次のような出力が得られるようにしなさい.

ほげお の 攻撃力 は 0.1 です
ほげお の 防御力 は 0.001 です

ただし,

  1. for文はそのまま書き換えず使うこと.
  2. キー khoge のキーの中に存在するかどうか調べる if 文を書いて,上記の print文はそれが True だったときだけ実行するようにする.

ループの応用 (pp.139-144)

C言語と同様に,Python にも while 文があります. for 文は

for  ループ変数  in  シーケンス:
    繰り返し実行するブロック

という構造でしたが, while 文は次のような構造です.

while 条件式:
    繰り返し実行するブロック
In [ ]:
for i in range(5):
    print(i)

上記と同じことを while でやるならこんなん(★ 条件式の部分を書き加えて完成させよう).

In [ ]:
i = 0
while :
    print(i)
    i += 1

これまたC言語と同様に, break文,continue文もあります.機能/使い方もC言語と同様で,次のようなものです.

  • break: あるブロックから一つ外に抜け出す.「for や while のループで,特定の条件が成り立ったらブロックから抜け出す」という時に使う,というのが代表的
  • continue: ループブロック内のそれ以降の内容を飛ばして,ブロックの最初に戻る.

次のコードの実行結果がどうなるか予想しなさい.その後,実行して動作を確認しなさい.

In [ ]:
for i in range(1, 11):
    if i % 3 == 0:
        break
    print(i)
In [ ]:
for i in range(1, 11):
    if i % 3 == 0:
        continue
    print(i)

C言語にはない機能として,「forwhileelse文が使える」というのがあります(p.143, 144).

関数の応用 (pp.144-150)

組み込み関数 int() は,引数として渡されたものを整数に変換して返す関数でした.

In [ ]:
int("10")

上記の例では引数は1つですが,以前も説明したように,実は2つ目の引数に自然数 p を指定すると,1つ目の引数の内容を p進法で表現された数と解釈して変換した数を10進数で返してくれるのでした.

In [ ]:
int("10", 2)
In [ ]:
int("10", 16)
In [ ]:
int("ff", 16)

このように,Pythonでは渡すことのできる引数のうち一部だけを指定しても動作するように関数を作ることができます. このような関数は,引数の一部にデフォルト値を指定して定義されています.

組み込み関数 int() のオンラインドキュメントを見てみましょう. https://docs.python.jp/3/library/functions.html#int

そこに記されている

int(x, base=10)

という表現は,

  • この関数は引数を2つとる
  • 2つ目の引数(base)のデフォルト値10 である

ということを表しています.デフォルト値の指定されている引数をデフォルト引数といいます. デフォルト引数については,呼び出し時に値が渡されなかった場合,デフォルト値が引数として指定されたのと同じ動作をすることになっています.

int() の例では,引数を1つしか指定しなかったら2つ目の引数に 10 を指定したことになる → 10進数と解釈して変換する,ということになります.

このようにデフォルト値を指定した関数は,上記の書き方をそのまま使って定義します. 以下の例で確認してみましょう.

In [ ]:
def echo(n, s="ほげ"):
    print(s*n)

★ 引数を1つだけ(nの方だけ)指定して関数 echo() を呼んでみましょう.

In [ ]:
# 第1引数だけ指定して echo を呼ぶ

★ 2つ目の引数も指定して呼んでみましょう.

In [ ]:
# 第2引数も指定(適当な文字列を指定しよう)して echo を呼ぶ

さて,C言語でもPythonでも,引数の順番には意味があります. 関数を呼び出す際には,通常は定義された順番どおりに引数を指定しないといけません. 例えば,次のようにするとエラーになります.

In [ ]:
int(16, "ff")

このことは,引数の多い関数では問題となりがちです.

In [ ]:
def fournumbers(x1, x3=3, x4=4, x2=2):
    print(x1, x2, x3, x4)
In [ ]:
fournumbers(1)
In [ ]:
fournumbers(1, 999)

この例はわざわざ混乱させるよう書き方をしている悪い例ですが,引数が多くなってくると,どれが何番目の引数かに気を使って書くのは大変です.

そこでPythonでは,関数の定義に使用されている引数の名前を使って引数を指定できるようになっています(引数のキーワード指定).

In [ ]:
fournumbers(x2=2, x1=1)

上記の例から明らかにように,キーワード指定する場合,本来の関数定義における引数の順序を守らなくても,ちゃんと解釈してくれます.

ただし,キーワード指定した引数の後にキーワード指定のない引数を書いて呼び出すことはできません. 以下はエラーになります.

In [ ]:
fournumbers(x2=2, 1, x3=3)

また,関数を定義する際には,デフォルト値を指定した引数より後にデフォルト値を指定しない引数を書くことはできません.例えば,次の関数定義はエラーになります.

In [ ]:
def fournumbers2(x3=3, x4 = 4, x1, x2 = 2):
    print(x1, x2, x3, x4)

つまり,関数定義の際は,引数にはまずはデフォルト値の指定のないものを並べ,その後にデフォルト値を指定したものを並べる,という書き方をしないといけません.

pp.147-150の「関数とローカル変数」の内容については,以前の回で一部をすでに学習していますので,ここでは触れません.

(よだんだよん) 引数のキーワード指定の話とローカル変数/変数のスコープの話を組み合わせると,C言語とPythonで一見異なる振る舞いをするように見える,嫌がらせのようなコードを書くことができます.

// C言語
int x1 = 1;
fournumbers(x1=111);  // 変数 x1 に 111 を代入してから,その値を関数に渡すことになる
printf("%d", x1);   // だからこの出力は 111
In [ ]:
# Python
x1 = 1
fournumbers(x1=111)  # この x1 は 関数 fournumbers のキーワード引数
print(x1)    # 出力は...

オブジェクトとしての組み込み型 (pp.152-162)

ここで学ぶことを掘り下げていくと,オブジェクト指向プログラミングというプログラミングの考え方につながっています.ただし,この授業ではそこへは向かいません.数理情報学科のみなさんは,3年前期「グラフィックス基礎及び実習」を履修すると, Java言語プログラミングを通じてオブジェクト指向プログラミング(とマウスによるボタン操作などを実現するグラフィカルユーザインタフェイス)の世界へ分け入ることができます.お楽しみに.

「リストの中から特定の要素を探してそれが何番目にあるか調べる」という処理を考えてみましょう.

In [ ]:
mcz = ["れに", "かなこ", "しおり", "あやか", "ももか"]

"しおり"mcz の何番目の要素ですか?」みたいな. こういう処理を何度も繰り返すのなら,今までの経験からすると,関数を定義するのが妥当そうですで. 以下は,実際にそういう機能を実現するために作った関数です.

(よだんだよん)見つからなかったときの動作が気になりますか?するどいですね.教科書でもこうなってますが,おそらく後述の `index`メソッドが見つからないと ValueError を吐く,という仕様なので,それに似せてるんだと思います.

In [ ]:
def find_index(the_list, target):
    idx = 0
    for item in the_list:
        if target == the_list[idx]:
            return idx
        idx = idx+1

使ってみましょう.

In [ ]:
find_index(mcz, "しおり")
In [ ]:
find_index(["ほげ", "ふが", "へな", 4649, 5963], 4649)

で,がんばって関数作ってみておいてなんなんですが,実は Python のリストには最初からこの関数と同様のことをする機能が備わっています.そっちを使ってみましょう.

In [ ]:
mcz.index("しおり")
In [ ]:
["ほげ", "ふが", "へな", 4649, 5963].index(4649)

なんだか見慣れない書き方(後の方が特に)ですが,ここで使っているのは,Pythonの組み込みデータ型であるリスト型のオブジェクトに対する index メソッド です...と言ってもオブジェクトとかメソッドとか,まだわけわかめですね.ちょっとずつ理解していきましょう.

C言語のような言語では,「データ」とそれに対する「処理の手続き」は完全に分かれています. データは「変数」などに格納し,それに対する処理の手続きは命令を並べて表現します.処理の手続きは「関数」としてまとめることもあります.

一方,オブジェクト指向と呼ばれるスタイルのプログラミング言語では,「データ」とそれに対する「処理」を関連付けて考えます.「データ」とそれに対する「処理」をひとまとめにした「もの」(オブジェクト, object)として扱うので,オブジェクト指向といいます. Python もオブジェクト指向のプログラミング言語です(純粋なオブジェクト指向言語とは言い難いのですが).

上記の変数 mcz["ほげ", "ふが", "へな", 4649, 5963] は,どちらもリストを表している,リスト型のオブジェクトです.リスト型のオブジェクトには,単にデータが格納されているだけでなく,それ自身を扱う処理の手続きがいろいろ備わっています.オブジェクトに備わった処理の手続きをメソッド(method)といいます.

メソッドは,データに対する処理の手続きを表しており,呼び出して使う,という意味では関数と似てます. しかし,使い方がまるで違い,

「オブジェクト」.「メソッド名」(引数...)

という形をとります. 以下の例では,リスト型のデータを格納した mcz という「オブジェクト」の index という「メソッド」を,「引数」に "しおり" を渡して呼び出しています.

In [ ]:
mcz.index("しおり")

この index メソッドはリスト型のオブジェクトに備わったものですので,リストを変数に格納せず直接呼び出しても構いません. だからこんな書き方もできちゃうわけです.

In [ ]:
["ほげ", "ふが", "へな", 4649, 5963].index(4649)

次は,リスト型オブジェクトのreverseメソッドの使用例です.

In [ ]:
mcz.reverse()
print(mcz)

実行結果から分かるように,mczの要素が逆順になっています.このメソッドはオブジェクト自身に作用して内容を変更していることがわかりますね.このセルをもう一度実行すると元に戻ります.

このように,Python では,リスト文字列ディクショナリなどの標準で用意されたデータ型(組み込み型)に様々なメソッドが用意されており,それらを使うだけで複雑な処理を実現できるようになっています. 教科書の Chapter04 や Python のオンラインリファレンス( https://docs.python.jp/3/library/stdtypes.html )を見ると,そういうものが山ほどあるのがわかります.しかし,これらを全部覚えるなんてことはしなくて結構です. 必要になるたびに教科書やオンラインリファレンスを参照して,そこに記された説明をもとに使ってみる,というのが正しい姿と言ってよいでしょう.

チェック

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('05note', In)
In [ ]: