
この回でできるようになること
- 01変数が使える範囲(スコープ)を説明する
- 02*args と **kwargs の中身を確かめる
- 03内側の関数とデコレータの仕組みを小さな例で見る
変数が見える範囲
関数の中で作った変数は、通常その関数の中だけで使えます。これがローカルスコープです。

関数の中で作った total が外から見えない! 迷子?

迷子ではないんだよ。関数の中だけで使う名前なんだ。外へ渡したいなら return を使おう。

外側の同名変数をうっかり上書きせずに済む利点もありますね。
total = 100
def calc():
total = 2 + 3
return total
print(calc())
print(total)
なぜ? 関数内の total と外の total は別の名前の場所。calc() の結果5を返しても、外の100はそのままです。

外の変数に頼りすぎず、引数と戻り値で受け渡すと追いやすいよ。
個数が変わる引数
*args は追加の位置引数をタプルで、**kwargs は名前付き引数を辞書で受け取ります。

合計する数が2個の日も、4個の日もあるんだ。

*args なら個数が変わっても受け取れるよ。中身はタプルなので for で順番に使えるんだ。

**kwargs は『名前→値』の辞書で受け取る形ですね。
def total(*numbers):
answer = 0
for n in numbers:
answer += n
return answer
print(total(2, 3))
print(total(2, 3, 4))
なぜ? numbers は1回目が(2, 3)、2回目が(2, 3, 4)。個数に合わせて足します。

**kwargs は print(kwargs) で辞書の姿を見てみよう。
関数を包む考え方
関数の中に別の関数を作れます。外側の値を覚えた関数を返すとクロージャ、別の関数を包むしくみをデコレータと呼びます。

『2倍する係』を作る関数って、関数が工場みたい!

そのたとえ、いいね。中の関数が外で受け取った倍率を覚えているんだよ。

まずは動きを確認して、@を使うデコレータはその応用として考えます。
def make_multiplier(factor):
def multiply(value):
return value * factor
return multiply
double = make_multiplier(2)
print(double(5))
なぜ? double は factor=2 を覚えた multiply。double(5) で5×2になります。デコレータも関数を受け取って別の関数を返す仕組みを利用します。

@decorator は『元の関数を包み直す』短い書き方。最初は関数を返せることが分かれば十分だよ。

関数の中に関数まで出てきた! ほかにも何かある?

あるよ。でも一度に覚えなくて大丈夫。開いて動きを見て、必要になったときに戻ってこようね。

小さな例なら、引数や戻り値とのつながりを確かめられそうです。
もう一歩進みたい人へ
名前付きの値をまとめて受け取る
def show(**data):
print(data)
show(name="ROBORON", color="blue")**data は {'name': 'ROBORON', 'color': 'blue'} という辞書を受け取ります。
空のリストを初期値にするとき
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("リンゴ"))
print(add_item("バナナ"))2回目は新しいリストを作るため、リンゴが残りません。引数に [] を直接置くと、同じリストが呼び出し間で共有されます。
デコレータのいちばん小さな形
def cheer(func):
def wrapped():
print("準備OK!")
func()
return wrapped
@cheer
def greet():
print("こんにちは!")
greet()@cheer は greet を wrapped で包む書き方です。元のあいさつの前に『準備OK!』を加えます。
おまけ:ROBORONとじゃんけん
import random
def robot_hand():
return random.choice(["ぐー", "ちょき", "ぱー"])
print("ROBORONの手:", robot_hand())random.choice() はリストから1つを選びます。結果は実行するたびに変わる場合があります。公平な勝負にするなら、手の選び方や試す回数も考えてみよう。
予想して、理由まで確かめよう
答えを選んだら、説明を読んでから実行欄でも試してみよう。
外側 total=100、関数内 total=5 の例で、print(total) は?
答えを選ぶと理由が表示されます。

小さな練習:FizzBuzzを関数で作ろう
1〜15を順に調べ、3と5の両方で割り切れたら FizzBuzz、3だけなら Fizz、5だけなら Buzz、その他は数字を表示しよう。
ヒント:両方の条件を最初に調べます。余りは % で計算できます。
解き方の一例と理由を見る
def fizzbuzz(limit):
for n in range(1, limit + 1):
if n % 15 == 0:
print("FizzBuzz")
elif n % 3 == 0:
print("Fizz")
elif n % 5 == 0:
print("Buzz")
else:
print(n)
fizzbuzz(15)15は3と5の両方で割り切れるため、最初の条件で FizzBuzz になります。
便利な書き方は、読める大きさで

一行で全部書けたらカッコいいかも!

短いことより、後で読んで分かることが大切なんだよ。複雑なときは名前を付けて段階を分けよう。

チームの人にも意図が伝わる書き方を選びます。
自分の手で動かそう
例題を選び、結果を予想してから「実行する」を押そう。値を変えると、どの行が結果を決めるか見えてくるよ。
書き換えて試せます。Tabキーは半角スペース4つ分です。
関数の内側と外側は別の範囲です。
この入力欄の使い方
コード内の input() に渡す値を1行ずつ書きます。input() がない例では空欄で大丈夫です。複数回呼ぶコードでは上から順に使います。
準備できました。
実行結果
実行すると、ここに結果を表示します。
Pythonは閲覧中の端末内で動作します。

見える範囲と、受け取り方。 今日覚えた道具を、別の値でも試してみよう。自分で理由を説明できたら、とてもいい進歩なんだよ。