この資料中に説明なくページ番号が出てくる場合,教科書のページ番号を表しています.
ディクショナリ(辞書)の話を復習しよう.以下の内容は,前回の課題B-1そのままです.
以下のセルを修正して,変数 hoge
が次のようなキーと値のペアを持つディクショナリとなるようにしなさい.
キー | 値 |
---|---|
名前 | "ほげお" |
HP | 18 |
MP | 999 |
# ディクショナリ hoge を定義する
★ 次の指示にしたがって hoge
の内容を変更しなさい.
MP
の値 999
は間違いで,本当は 0
だった.修正しよう攻撃力
値 0.1
を追加防御力
値 0.001
を追加# ここに hoge の内容を変更する処理を書く
print(hoge)
★ 以下の関数を,次の実行例のような結果が得られるように修正しなさい
<実行例>
Wizard(hoge)
ほげお は魔法使えません
# 魔法使い判定関数 MP が 0 より大きければ「魔法使い」
#
def Wizard(p):
if p > 0: # この行修正必要
print(p, "は魔法使いです") # この行修正必要
else:
print(p, "は魔法使えません") # この行修正必要
Wizard(hoge)
以下を実行すると変な出力が得られる.
for k in [ "攻撃力", "防御力", "すばやさ"]:
print(hoge["名前"], "の", k, "は", k, "です")
★ これを修正して,次のような出力が得られるようにしなさい.
ほげお の 攻撃力 は 0.1 です
ほげお の 防御力 は 0.001 です
ただし,
for
文はそのまま書き換えず使うこと.k
が hoge
のキーの中に存在するかどうか調べる if
文を書いて,上記の print
文はそれが True
だったときだけ実行するようにする.C言語と同様に,Python にも while
文があります. for
文は
for ループ変数 in シーケンス:
繰り返し実行するブロック
という構造でしたが, while
文は次のような構造です.
while 条件式:
繰り返し実行するブロック
for i in range(5):
print(i)
上記と同じことを while
でやるならこんなん(★ 条件式の部分を書き加えて完成させよう).
i = 0
while :
print(i)
i += 1
これまたC言語と同様に, break
文,continue
文もあります.機能/使い方もC言語と同様で,次のようなものです.
break
: あるブロックから一つ外に抜け出す.「for や while のループで,特定の条件が成り立ったらブロックから抜け出す」という時に使う,というのが代表的continue
: ループブロック内のそれ以降の内容を飛ばして,ブロックの最初に戻る.次のコードの実行結果がどうなるか予想しなさい.その後,実行して動作を確認しなさい.
for i in range(1, 11):
if i % 3 == 0:
break
print(i)
for i in range(1, 11):
if i % 3 == 0:
continue
print(i)
C言語にはない機能として,「for
やwhile
でelse
文が使える」というのがあります(p.143, 144).
組み込み関数 int()
は,引数として渡されたものを整数に変換して返す関数でした.
int("10")
上記の例では引数は1つですが,以前も説明したように,実は2つ目の引数に自然数 p
を指定すると,1つ目の引数の内容を p
進法で表現された数と解釈して変換した数を10進数で返してくれるのでした.
int("10", 2)
int("10", 16)
int("ff", 16)
このように,Pythonでは渡すことのできる引数のうち一部だけを指定しても動作するように関数を作ることができます. このような関数は,引数の一部にデフォルト値を指定して定義されています.
組み込み関数 int()
のオンラインドキュメントを見てみましょう.
https://docs.python.jp/3/library/functions.html#int
そこに記されている
int(x, base=10)
という表現は,
base
)のデフォルト値は 10
であるということを表しています.デフォルト値の指定されている引数をデフォルト引数といいます. デフォルト引数については,呼び出し時に値が渡されなかった場合,デフォルト値が引数として指定されたのと同じ動作をすることになっています.
int()
の例では,引数を1つしか指定しなかったら2つ目の引数に 10
を指定したことになる → 10進数と解釈して変換する,ということになります.
このようにデフォルト値を指定した関数は,上記の書き方をそのまま使って定義します. 以下の例で確認してみましょう.
def echo(n, s="ほげ"):
print(s*n)
★ 引数を1つだけ(n
の方だけ)指定して関数 echo()
を呼んでみましょう.
# 第1引数だけ指定して echo を呼ぶ
★ 2つ目の引数も指定して呼んでみましょう.
# 第2引数も指定(適当な文字列を指定しよう)して echo を呼ぶ
さて,C言語でもPythonでも,引数の順番には意味があります. 関数を呼び出す際には,通常は定義された順番どおりに引数を指定しないといけません. 例えば,次のようにするとエラーになります.
int(16, "ff")
このことは,引数の多い関数では問題となりがちです.
def fournumbers(x1, x3=3, x4=4, x2=2):
print(x1, x2, x3, x4)
fournumbers(1)
fournumbers(1, 999)
この例はわざわざ混乱させるよう書き方をしている悪い例ですが,引数が多くなってくると,どれが何番目の引数かに気を使って書くのは大変です.
そこでPythonでは,関数の定義に使用されている引数の名前を使って引数を指定できるようになっています(引数のキーワード指定).
fournumbers(x2=2, x1=1)
上記の例から明らかにように,キーワード指定する場合,本来の関数定義における引数の順序を守らなくても,ちゃんと解釈してくれます.
ただし,キーワード指定した引数の後にキーワード指定のない引数を書いて呼び出すことはできません. 以下はエラーになります.
fournumbers(x2=2, 1, x3=3)
また,関数を定義する際には,デフォルト値を指定した引数より後にデフォルト値を指定しない引数を書くことはできません.例えば,次の関数定義はエラーになります.
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
# Python
x1 = 1
fournumbers(x1=111) # この x1 は 関数 fournumbers のキーワード引数
print(x1) # 出力は...
ここで学ぶことを掘り下げていくと,オブジェクト指向プログラミングというプログラミングの考え方につながっています.ただし,この授業ではそこへは向かいません.数理情報学科のみなさんは,3年前期「グラフィックス基礎及び実習」を履修すると, Java言語プログラミングを通じてオブジェクト指向プログラミング(とマウスによるボタン操作などを実現するグラフィカルユーザインタフェイス)の世界へ分け入ることができます.お楽しみに.
「リストの中から特定の要素を探してそれが何番目にあるか調べる」という処理を考えてみましょう.
mcz = ["れに", "かなこ", "しおり", "あやか", "ももか"]
「"しおり"
は mcz
の何番目の要素ですか?」みたいな.
こういう処理を何度も繰り返すのなら,今までの経験からすると,関数を定義するのが妥当そうですで.
以下は,実際にそういう機能を実現するために作った関数です.
(よだんだよん)見つからなかったときの動作が気になりますか?するどいですね.教科書でもこうなってますが,おそらく後述の `index`メソッドが見つからないと ValueError を吐く,という仕様なので,それに似せてるんだと思います.
def find_index(the_list, target):
idx = 0
for item in the_list:
if target == the_list[idx]:
return idx
idx = idx+1
使ってみましょう.
find_index(mcz, "しおり")
find_index(["ほげ", "ふが", "へな", 4649, 5963], 4649)
で,がんばって関数作ってみておいてなんなんですが,実は Python のリストには最初からこの関数と同様のことをする機能が備わっています.そっちを使ってみましょう.
mcz.index("しおり")
["ほげ", "ふが", "へな", 4649, 5963].index(4649)
なんだか見慣れない書き方(後の方が特に)ですが,ここで使っているのは,Pythonの組み込みデータ型であるリスト型のオブジェクトに対する index
メソッド です...と言ってもオブジェクトとかメソッドとか,まだわけわかめですね.ちょっとずつ理解していきましょう.
C言語のような言語では,「データ」とそれに対する「処理の手続き」は完全に分かれています. データは「変数」などに格納し,それに対する処理の手続きは命令を並べて表現します.処理の手続きは「関数」としてまとめることもあります.
一方,オブジェクト指向と呼ばれるスタイルのプログラミング言語では,「データ」とそれに対する「処理」を関連付けて考えます.「データ」とそれに対する「処理」をひとまとめにした「もの」(オブジェクト, object)として扱うので,オブジェクト指向といいます. Python もオブジェクト指向のプログラミング言語です(純粋なオブジェクト指向言語とは言い難いのですが).
上記の変数 mcz
や ["ほげ", "ふが", "へな", 4649, 5963]
は,どちらもリストを表している,リスト型のオブジェクトです.リスト型のオブジェクトには,単にデータが格納されているだけでなく,それ自身を扱う処理の手続きがいろいろ備わっています.オブジェクトに備わった処理の手続きをメソッド(method)といいます.
メソッドは,データに対する処理の手続きを表しており,呼び出して使う,という意味では関数と似てます. しかし,使い方がまるで違い,
「オブジェクト」.「メソッド名」(引数...)
という形をとります.
以下の例では,リスト型のデータを格納した mcz
という「オブジェクト」の index
という「メソッド」を,「引数」に "しおり"
を渡して呼び出しています.
mcz.index("しおり")
この index
メソッドはリスト型のオブジェクトに備わったものですので,リストを変数に格納せず直接呼び出しても構いません.
だからこんな書き方もできちゃうわけです.
["ほげ", "ふが", "へな", 4649, 5963].index(4649)
次は,リスト型オブジェクトのreverse
メソッドの使用例です.
mcz.reverse()
print(mcz)
実行結果から分かるように,mcz
の要素が逆順になっています.このメソッドはオブジェクト自身に作用して内容を変更していることがわかりますね.このセルをもう一度実行すると元に戻ります.
このように,Python では,リスト,文字列,ディクショナリなどの標準で用意されたデータ型(組み込み型)に様々なメソッドが用意されており,それらを使うだけで複雑な処理を実現できるようになっています. 教科書の Chapter04 や Python のオンラインリファレンス( https://docs.python.jp/3/library/stdtypes.html )を見ると,そういうものが山ほどあるのがわかります.しかし,これらを全部覚えるなんてことはしなくて結構です. 必要になるたびに教科書やオンラインリファレンスを参照して,そこに記された説明をもとに使ってみる,というのが正しい姿と言ってよいでしょう.
TAさんに課題Aのチェックを受ける際は,以下のセルを実行して「OK!」が出ているようにしてください.
# 以下のコードは,この 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)