『退屈なことは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件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です