PYTHON はじめの一歩 / LESSON 10

関数を育てよう。

関数を使いこなすための少し進んだ道具を学びます。難しい書き方も、まずは小さな例で意味を確かめよう。

学びを始める

見える範囲と、受け取り方。 | 動画なしでも学べます

関数を育てよう。をあおい・はる・AI先生・ROBORONと考えるイラスト
見える範囲と、受け取り方。
GOAL

この回でできるようになること

  • 01変数が使える範囲(スコープ)を説明する
  • 02*args と **kwargs の中身を確かめる
  • 03内側の関数とデコレータの仕組みを小さな例で見る
ことばの窓
01 / EXPLORE

変数が見える範囲

関数の中で作った変数は、通常その関数の中だけで使えます。これがローカルスコープです。

あおい

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

AI先生

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

はる

外側の同名変数をうっかり上書きせずに済む利点もありますね。

実際のコードまず結果を予想してみよう
total = 100
def calc():
    total = 2 + 3
    return total

print(calc())
print(total)
実行すると5 / 100

なぜ? 関数内の total と外の total は別の名前の場所。calc() の結果5を返しても、外の100はそのままです。

目で見てわかる変数が見える範囲
図10-1 同じ名前でも、見える範囲が違います。
図10-1 同じ名前でも、見える範囲が違います。
ROBORONのチェック!

外の変数に頼りすぎず、引数と戻り値で受け渡すと追いやすいよ。

02 / EXPLORE

個数が変わる引数

*args は追加の位置引数をタプルで、**kwargs は名前付き引数を辞書で受け取ります。

あおい

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

AI先生

*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))
実行すると5 / 9

なぜ? numbers は1回目が(2, 3)、2回目が(2, 3, 4)。個数に合わせて足します。

目で見てわかる個数が変わる引数
図10-2 *args は渡された値をひと組のタプルにします。
図10-2 *args は渡された値をひと組のタプルにします。
ROBORONのチェック!

**kwargs は print(kwargs) で辞書の姿を見てみよう。

03 / EXPLORE

関数を包む考え方

関数の中に別の関数を作れます。外側の値を覚えた関数を返すとクロージャ、別の関数を包むしくみをデコレータと呼びます。

あおい

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

AI先生

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

はる

まずは動きを確認して、@を使うデコレータはその応用として考えます。

実際のコードまず結果を予想してみよう
def make_multiplier(factor):
    def multiply(value):
        return value * factor
    return multiply

double = make_multiplier(2)
print(double(5))
実行すると10

なぜ? double は factor=2 を覚えた multiply。double(5) で5×2になります。デコレータも関数を受け取って別の関数を返す仕組みを利用します。

目で見てわかる関数を包む考え方
図10-3 内側の関数が倍率を覚えます。
図10-3 内側の関数が倍率を覚えます。
ROBORONのチェック!

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

あおい

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

AI先生

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

はる

小さな例なら、引数や戻り値とのつながりを確かめられそうです。

もう一歩進みたい人へ

名前付きの値をまとめて受け取る
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つを選びます。結果は実行するたびに変わる場合があります。公平な勝負にするなら、手の選び方や試す回数も考えてみよう。

04 / YOUR TURN

予想して、理由まで確かめよう

答えを選んだら、説明を読んでから実行欄でも試してみよう。

チャレンジどれになるかな?

外側 total=100、関数内 total=5 の例で、print(total) は?

答えを選ぶと理由が表示されます。

PUT IT TOGETHER

小さな練習: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 になります。

COFFEE BREAK

便利な書き方は、読める大きさで

あおい

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

AI先生

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

はる

チームの人にも意図が伝わる書き方を選びます。

05 / RUN PYTHON

自分の手で動かそう

例題を選び、結果を予想してから「実行する」を押そう。値を変えると、どの行が結果を決めるか見えてくるよ。

例題を選ぶ

書き換えて試せます。Tabキーは半角スペース4つ分です。

関数の内側と外側は別の範囲です。

この入力欄の使い方

コード内の input() に渡す値を1行ずつ書きます。input() がない例では空欄で大丈夫です。複数回呼ぶコードでは上から順に使います。

準備できました。

実行結果

実行すると、ここに結果を表示します。

Pythonは閲覧中の端末内で動作します。

AI先生からひとこと

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