Pythonプログラミング

【Python】13.関数定義(2)変数を使った関数

グローバル変数とローカル変数

defで定義された関数の中は外から独立しています。変数が有効な範囲をスコープと呼びます。
変数はグローバル変数かローカル変数かのどちらかによって、呼び出せる範囲が違います。
グローバル変数はどの範囲からもアクセスできる変数です。宣言なくどこでも利用できますが、関数の中からは変更できません。
対してローカル変数は、スコープと呼ばれる有効範囲が決まっています。
例えば、以下の例では関数messageはスコープ外にあるgreeを読む事ができず、エラーになってしまいます。

gree = "Hello"

def message():
    gree += " "
    gree += "World"
    print(gree)

message()

そこで、ローカル変数をグローバル変数に変更するグローバル宣言という処理を行います。
global greeと「greeはグローバル変数である」という宣言をすると、関数外にあっても参照する事ができます。

gree = "Hello"

def message():
    global gree
    gree += " "
    gree += "World"
    print(gree)

message()

出力結果
Hello World

無事に出力されました。
次は数字も入れて計算を混ぜてみましょう。

gree= "Hello"
a = 5
b = 3

def sum(x, y):
    #ローカル変数
    a = 3
    #グローバル宣言
    global gree
    gree += "World"
    print(gree + str(a))
    return x + y

num = sum(a, b)
print(num)
print(gree + " " + str(a))

出力結果
HelloWorld3
8
HelloWorld 5

上の場合、グローバル宣言部分を消すと、関数内からgreeを参照する事ができずエラーになり、グローバル宣言をするとgreeがどこからでも参照できるルールに変わり出力結果が出ます。

では、呂布がランダムに敵を攻撃する関数を作ってみましょう。
まず敵武将は夏侯惇、夏侯淵、あとご先祖様ですが夏侯嬰に攻撃するとします。
乱数で1〜10を作り、10ならクリティカルヒットで倒した事にし、6〜9ならダメージを与えます。それ以下は全て躱される事にしましょう。

import random
busyou = ["夏侯惇", "夏侯淵", "夏侯嬰"]

def attack(teki):
    print("呂布は、" + teki + "を攻撃した。")
    hit = random.randint(1,10)
    if hit == 10:
        print( teki + "を倒した!" )
    elif hit > 6:
        print(teki + "に、" + str(hit) + "のダメージを与えた!")
    else:
        print("ミス!" + teki + "は攻撃を素早く躱した")

for teki in busyou:
    attack(teki)
  1. 乱数モジュールをインポートします。
  2. 敵武将を定義します。
  3. 関数を定義します。名前はattackで引数をtekiとします。
  4. 呂布が引数のtekiを攻撃するとします。
  5. hit変数を作り、1から10までの乱数を格納します。hitは関数内で作っているのでローカル変数です。
  6. もしも10であったら一撃とします。
  7. そうでなく、かつ6以上であれば、tekiに対しhit値分ののダメージを与えます。
  8. それ以外はミスだとします。
  9. for文を開始。名前は先程のtekiをここで定義します。グローバル変数なので関数内に参照させる事ができます。引数はbusyouで、リストがある限り繰り返します。
  10. 内容はその時のtekiを引数にattackを実行します。

標準入力で敵兵力を設定する

では、関ヶ原の合戦をシュミレーションしてみます。標準入力を使って西軍側の兵力を設定し、辞書に東軍各部隊の兵力を設定します。
味方兵1名は敵兵1名と対消滅するものとします。
とりあえず小早川秀秋は東軍扱いにします。
入力した値が東軍兵力に削られる関数を作ってみます。

troops = int(input())
easternArmy = {"小早川秀秋" : 15600, "池田輝政" : 4500, "黒田長政" : 5400,"細川忠興" : 5000}

def attack(busyou):
    print(busyou + "隊は西軍を攻撃しました")

def surviving(troops):
    print("敵兵力残り" + str(troops) + "です")

for busyou, remainingArmy in easternArmy.items():
    attack(busyou)
    troops -= remainingArmy
    surviving(troops)
  1. 標準入力。東軍部隊を辞書に設定。
  2. 関数をattack、引数をbusyouで作成。
  3. 武将の行動を出力。関数をsurviving、引数を入力値にします。
  4. 敵兵力を入力値として文字列で出力します。
  5. for文開始。変数名はbusyou、remainingArmyと名付け、西軍の辞書がある間ループします。辞書は組み合わせの取得なのでitems()を使用します。
  6. ループ内でattackを引数busyouで実行します。
  7. 入力値からその時のremainingArmyを引きます。
  8. survivingを引数troopsで実行すると、troops内のprintで西軍の残存兵力が出力されます。

可変長引数

引数の長さが可変の引数を可変長引数と言います。
どういう数の引数を渡しても処理する関数を作る事ができます。
可変長引数の指定には、関数の引数に(アスタリスク)または*をつけると可変長引数であると定義されます。
実際にやってみましょう。

比較のため、普通の引数を関数に入れてみます。

def variableArgs(args):
print(args)

variableArgs(“関羽”)

これを実行すると「関羽」という実行結果になります。
この引数を仮に「(“関羽”, “呂布”,”甘寧”)」と複数にするとエラーになってしまいます。
そこで、引数argsにアスタリスクをつけて可変長引数にします。

def variableArgs(*args):
    print(args)

variableArgs("関羽", "呂布","甘寧")

出力結果
(‘関羽’, ‘呂布’, ‘甘寧’)

と、複数の値を受け付けられるようになりました!
次は応用して、リストのように可変長引数から複数の値を取り出して蜀の五虎大将が出陣するコードを書きましょう。
ところで、第一引数が先に使われるというわけではないので、後に登場するパターンにしてみます。

def syoku(koudou, *names):
    for name in names:
        print("武将、" + name + "が" + koudou + "出陣!")

syoku("兵を率いて", "関羽", "張飛", "趙雲", "馬超")
  1. 関数定義。名前はsyokuで第一引数koudou、第二引数を可変長引数にしてnamesにします。
  2. ループ開始。変数名はnameでnamesがある間繰り返します。
  3. 出力します。第一引数に入れたものが行動なので、第二引数以降が先にでて、次に第一引数の行動をする事にしてみます。
  4. 蜀の第一引数が行動なので、兵を率いる事にします。第二引数以降は武将名です

出力結果
武将、関羽が兵を率いて出陣!
武将、張飛が兵を率いて出陣!
武将、趙雲が兵を率いて出陣!
武将、馬超が兵を率いて出陣!

リストから取り出したように使えました!
黄忠をわすれましたね・・・。

デフォルト値

何も入力されていないの標準となる値をデフォルト値と言います。
ゼロである事もありますし、例えば100などの数値から減算する可能性もあるでしょう。
デフォルト値は引数にイコールをつける事で設定できます。

def default(myName = "名前を入れて下さい!"):
    print("私は" + myName)

#値を入れて出力
default("梅木千世")
#値を入れずに出力
default()

出力結果
私は梅木千世
私は名前を入れて下さい!

値を入れた場合は入れた文字列が表示され、
無い場合はデフォルトで入っている入力の要求などを出す、などの使い方ができます。

キーワード引数

賢明な読者は気づいたんじゃないかと思いますが、デフォルト値の入っている引数は名前がついているので、どの引数にどの値を渡すのかを「引数名=値」の形式で指定できます。いくつかの実例を入れてみます。

def function01(a = "WebdesignLink" , b = "デザインに関するリンクサイト"):
    print(a + "は" + b + "です")

#デフォルト値だけを出力
function01()
#両方の引数に代入
function01("このブログ" , "古物商のサイト")
#片方の引数だけ代入
function01("旅行体験記")
#引数の順番を入れ替える
function01(b = "過去話も混ざります" , a = "格闘技をしていた人")
#aだけ代入
function01(a = "ところで")
#bだけ代入
function01(b = "デザインサイトじゃないですか?")

出力結果
WebdesignLinkはデザインに関するリンクサイトです
このブログは古物商のサイトです
旅行体験記はデザインに関するリンクサイトです
格闘技をしていた人は過去話も混ざりますです
ところではデザインに関するリンクサイトです
WebdesignLinkはデザインサイトじゃないですか?です

これをキーワード引数と呼びます。これにすると、値の順番を決めなくてよくなります。
便利ですね!

コメントを残す

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