『退屈なことはPythonにやらせよう』その3 (5章:辞書型、データ構造)
Python初心者が勉強中です。
過程を記録するために書いているブログです。
今回はPythonの
- 辞書型
- データ構造
の章となっています。
前回の記事はこちら。
目次
今回の5章では、Pythonの辞書型とデータ構造について勉強しました。
演習プロジェクトもかなり複雑になってきました。
Pythonの辞書型
辞書型の基本
Pythonではここまで、整数型、文字列型、そしてリストなどを学んできました。
今回は辞書というデータ型について学びます。
以下の例がPythonにおける辞書型になります。
#辞書型は{ }で囲む
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
print(tamago["ra-men"])
#出力は "noodle"
tamago["ra-men"] = "oishi"
print(tamago["ra-men"])
#出力は "oishi"
辞書型は
変数名 = { キー : 値 (=value) }
で定義されます。
変数名[キー] = 値 とすると、新しい値を代入(新しい値に更新)することができます。
また、カンマで区切られたキーと値のペア同士には順番がありません。
ここまでをまとめると、
Pythonの辞書型は
- { } (波かっこ)で囲われている
- 中の要素は キー: 値 の形をしている
- 要素は変更可能
- 要素同士には順番がない
ということになります。
辞書型のメソッド1 (keys, values, items)
辞書型で使える基本の3つのメソッドをみていきましょう。
- keys()
- values()
- items()
です。
実際のコードではこのような感じで書かれます。
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
#keys
for k in tamago.keys():
print(k)
#出力は "ra-men", "oyako-don", "omlet"
for k in tamago:
print(k)
#出力は "ra-men", "oyako-don", "omlet"
#何もつけなくてもkeyを参照している
keys()メソッドでは、辞書の中のキーを出力できます。(実際は各要素は改行されて出てきます。今は便宜上カンマで表しています)
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
#values
for v in tamago.keys():
print(v)
#出力は "noodle", "gohan", "protein"
values()メソッドでは、辞書の中の値を出力できます。(実際は各要素は改行されて出てきます。今は便宜上(略))
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
#items
for k in tamago.items():
print(k)
#出力は ("ra-men", "noodle"), ("oyako-don", "gohan"), ("omlet", "protein")
items()メソッドでは、辞書の中のキーと値をタプルとして出力できます。(実際は各要素は改行されて(略))
以下のように、forの変数を二つ指定(複数指定)すると、キー、値の順番で出力することができます。
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
#items
for k, v in tamago.items():
print(k +"は" + v + "です")
#出力は ra-menはnoodleです, oyako-donはgohanです, omletはproteinです
また、
for "ra-men" in tamago.keys()
#出力は True
とすると、任意のキー(または値)が辞書の中に存在するか確認することができます。
辞書型のメソッド2 (get, setdefault)
先ほどkeys()メソッドで、辞書の中に任意のキーがあるか確認できると説明がありました。
それをさらに便利に使えるメソッドがget()メソッドです。
このget()メソッドでは
- 辞書の中に任意の値があるか確認
- 無かった時に出力する値を指定することができる
keys()メソッドでは、調べたいキーが辞書に含まれない場合、エラーを吐いてそこで止まってしまいます。
#get()
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
print(str(tamago.get("ra-men", 0) + "です")
#出力は noodleです
print(str(tamago.get("soba", 0) + "です")
#出力は 0です
いちいち辞書のキーの一覧を眺めなくて済むので便利です。
また、「そのキーが存在しないときだけ辞書に追加する」という便利なメソッドがあります。
この超便利なのが、setdefault()メソッドです。
#setdefault()
tamago = {"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein"}
tamago.setdefault("toast", "bread")
# 出力は"bread"で、{"ra-men" : "noodle", "oyako-don" : "gohan", "omlet" : "protein", "toast" : "bread"}となる。
tamago.setdefault("toast", "pan")
# 出力は "bread"となる。既に"toast"のキーが存在しているため、上書きされない。
キーと値の組を渡すと、辞書に追加することができる。
キーが既に辞書の中に存在している場合は、元の値を上書きせず、元の値を保持する。
辞書型のメソッドではないけど辞書型にちょっと便利なやつ (pprint)
pprintモジュールをインポートすることで、
- pprint.pprint
- pprint.pformat
が使えるようになります。
要素の順番がばらばらの辞書型を綺麗に並べることができます。
pprintのほうは結果を出力し、pformatのほうは並べ替えを行うだけです。
Pythonのデータ構造
代数的記法
将棋やチェスなどのマス目を、座標を用いて表す場合があると思います。
棋譜などで書かれる、「▲7六歩」とか、「△3四歩」のようなやつですね。
将棋のマスは縦が九マス、横は9マスとなっています。(▲と△はプレイヤー1、プレイヤー2みたいな感じです)
「プレイヤー名、横の座標、縦の座標、コマの種類」とすることで、
将棋盤もコマも無くてもゲームを再現することができます。
この章では、Pythonの辞書を用いて、3目並べ(まるばつゲーム)を再現するコードを書きました。
(日本語訳の本の方には、さらにゲームの勝敗を評価するコードもついたコードへのリンクがあります)
#マス目
the_board = {"top-L" : " ", "top-M" : " ", "top-R" : " ",
"mid-L" : " ", "mid-M" : " ", "mid-R": " ",
"low-L" : " ", "low-M" : " ", "low-R" : " "}
#マス目を出力する関数
def print_board(board):
print(board["top-L"] + "|" + board["top-M"] + "|" + board["top-R"])
print("-+-+-")
print(board["mid-L"] + "|" + board["mid-M"] + "|" + board["mid-R"])
print("-+-+-")
print(board["low-L"] + "|" + board["low-M"] + "|" + board["low-R"])
print("-+-+-")
#実際のゲーム
turn = "X"
for i in range(9):
print_board(the_board)
print(turn + "の番です。何処に打つ?")
move = input()
the_board[move] = turn
if turn == "X":
turn = "O"
else:
turn = "X"
print_board(the_board)
これを実行すると、マス目が表示され、9回の間、位置を指定することで「まるばつゲーム」ができます。
少し遊んでみて気づいたのですが、このゲーム、
相手が置いたところにも置けてしますのです
こうなってしますと、ひたすらにmid-M、つまりは真ん中のマスをひたすら取り合うだけのクソゲーになってしまいますね…
勝利判定がされていないことも本文中で触れられており、翻訳をされた方がコードをGithubに載せてくれています。
見たところ、かなりしっかり遊べるコードになってて「ぴゃ~」って思いました…
自分でもこれくらいのコードが書き上げられるように頑張ります。
演習プロジェクト
5章 演習プロジェクト(持ち物リスト)
RPGとかでよくある持ち物リストを作る課題です。
マスターボール × 99 こ、ふしぎなアメ × 20 こ
とか、そんな感じのやつですね。
課題1:持ち物リストを出力
与えられた持ち物リストを、forループで出力するコードを書く課題です。
#inventory
def display_inventory(inventory):
print("持ち物リスト: ")
item_total = 0
for k, v in inventory.items():
item_total += v
print(v, k)
print("アイテム総数: " + str(item_total))
stuff = {"ロープ" : 1, "たいまつ" : 6, "金貨" : 42, "手裏剣" : 1, "矢" : 12}
display_inventory(stuff)
"""
出力
持ち物リスト:
1 ロープ
6 たいまつ
42 金貨
1 手裏剣
12 矢
アイテム総数: 62
"""
本のほうでは順番がちょっと違うのですが、pprintなどを使ってもその順番にならないので、ちょっと原因が分かりません…
課題2:持ち物リスト用に、リストから辞書に移す
ドロップアイテムを持ち物リストに追加するようなイメージです。
#add items
def add_to_inventory(inventory, added_items):
for item in added_items:
inventory.setdefault(item, 0)
inventory[item] += 1
return inventory
inv = {"金貨" : 42, "ロープ" : 1}
dragon_loot = ["金貨", "手裏剣", "金貨", "金貨", "ルビー"]
inv = add_to_inventory(inv, dragon_loot)
display_inventory(inv) #display_inventory関数は課題1のもの
"""
出力
持ち物リスト:
45 金貨
1 ロープ
1 手裏剣
1 ルビー
アイテム総数: 48
"""
簡単に説明をしておくと、
- ドロップアイテムのリスト(dragon_loot)をforループで順番に参照し、itemという変数にしまいます。
- setdefault()メソッドを使うことで、持ち物リストになければ追加(値は0にしておく)
- すでにあれば値は変更されないので、値に1を加える
という感じです。
これもまたちょっと順番が違うんですが、どうしてなんだろう…?
まとめ
Pythonの辞書型は
- {}で囲まれる
- キーと値を持つ
- 順番は関係ない
便利なメソッドとしては
- keys() : キーを参照する
- values() : 値を参照する
- items() : キーと値をセットで参照する
- get() : キーを取得する。ない場合には、かわりに入れる値を指定できる
- setdefault() : 辞書に新しいペアを追加できる。キーがすでにあれば、値は変更されない。
以上です~。
次の記事はこちら↓(文字列と格闘しました)
“『退屈なことはPythonにやらせよう』その3 (5章:辞書型、データ構造)” に対して2件のコメントがあります。