Kodokon kodokon.com

関数:def、パラメーター、return、そしてスコープ

コードを再利用可能な関数へと構造化し、デフォルト値を使いこなし、変数のスコープを理解しましょう。

10 分 · 3 問

このレッスンを Kodokon で開く

ループと条件の書き方はすでに知っていますね。いよいよコードを構造化するときです。関数は、はっきりとした名前の裏に特定の仕事を切り離します。一度書き、一度テストすれば、あとはどこからでも呼び出せます。defが関数を宣言し、パラメーターが入力の値を受け取り、returnが結果を呼び出し元へ送り返します。見落とされがちなことをひとつ覚えておきましょう。returnのない関数はNoneを返します。

PYTHON
def net_price(price, tax_rate):
    total = price * (1 + tax_rate)
    return round(total, 2)

result = net_price(100, 0.2)
print(result)  # 120.0
この関数は二つのパラメーターを受け取り、returnで値を送り返す

デフォルト値は、いくつもの変種を作らずに関数を柔軟にします。必須のパラメーターのあとに宣言しましょう。呼び出すときは、キーワード引数currency="USD")があなたの意図を説明してくれます。実務のコードでは、関数のパラメーターが二つを超えたらすぐに使います。定義を開かなくても、呼び出しがはっきり読めるからです。

PYTHON
def format_price(amount, currency="EUR", digits=2):
    return f"{amount:.{digits}f} {currency}"

print(format_price(19.9))                  # 19.90 EUR
print(format_price(19.9, currency="USD"))  # 19.90 USD
print(format_price(19.9, digits=0))        # 20 EUR
キーワード引数を使えば、変わる部分だけを指定できる
PYTHON
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item("pen"))   # ['pen']
print(add_item("book"))  # ['book']
Noneパターンなら、呼び出しごとに新しいリストから始まる

スコープは、変数がどこに存在するかを決めます。関数の中で作られた変数はローカルです。呼び出しが終わると消えます。関数はグローバル変数を読むことはできますが、代入をすると新しいローカル変数が作られ、グローバルのほうはそのまま残ります。良い習慣として、グローバルを変更するのではなく、パラメーターを渡して結果を返しましょう。コードが予測しやすく、テストしやすくなります。

PYTHON
rate = 0.2

def apply_tax(price):
    return round(price * (1 + rate), 2)

def set_rate(new_rate):
    rate = new_rate  # local variable, no effect

print(apply_tax(100))  # 120.0
set_rate(0.1)
print(apply_tax(100))  # 120.0, the global is untouched
グローバルを読むのは動くが、代入するとローカルが作られる

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. return文のないPython関数は何を返しますか?
    • 0
    • None
    • 空文字列
    • エラーが投げられる
  2. なぜ def add_item(item, items=[]) を避けるべきなのですか?
    • デフォルトのリストは一度だけ作られ、呼び出し間で共有されるから
    • リストはデフォルト値として使えないから
    • 定義の時点でSyntaxErrorが投げられるから
  3. 同じ名前のグローバル変数があるときに、関数の中で変数へ代入するとどうなりますか?
    • Pythonがグローバル変数を変更する
    • Pythonがローカル変数を作り、グローバルはそのまま残る
    • Pythonが名前の衝突エラーを投げる