🐍

精読「独習Python」(ユーザー定義関数)

2024/12/30に公開



独習Python
「独習Python」は、初心者から中級者までを対象に、Pythonの基礎から応用までを体系的に学べる入門書で、豊富な例題と練習問題を通じて実践的なスキルを身につけられる一冊です。

関連記事

ユーザー定義関数の基本

ユーザー定義関数の基本構文

def 関数名(引数1, 引数2, ...):
    """
    関数の説明文(オプション)
    """
    処理内容
    return 戻り値(オプション)

関数名

小文字とアンダースコア(snake_case) で記述する

def calculate_area():
    pass

def get_user_input():
    pass

動詞を使う

def get_user_data():         # ユーザーデータを取得する
    pass

def set_user_name(name):     # ユーザー名を設定する
    pass

def add_item(item):          # アイテムを追加する
    pass

def remove_item(item):       # アイテムを削除する
    pass

def calculate_total_price(): # 合計金額を計算する
    pass

def update_record():         # レコードを更新する
    pass

def validate_email(email):   # メールアドレスを検証する
    pass

def print_report():          # レポートを印刷する
    pass

仮引数と実引数

仮引数(parameter):関数を定義する際に、その関数が受け取る入力を表す変数のこと

def greet(name):  # nameは仮引数
    print(f"Hello, {name}!")

実引数(argument):関数を呼び出す際に、仮引数に実際に渡される値のこと

greet("Alice")  # "Alice"は実引数

戻り値

関数が実行後に呼び出し元に返すデータのこと

def function_name():
    # 処理
    return value  # 戻り値を返す

変数の有効範囲(スコープ)

スコープとは、コードの中での変数の有効範囲のこと。コード全体から参照できるグローバルスコープと、定義された関数の中でのみ参照できるローカルスコープに分類できる

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

グローバルスコープを持つ変数のことをグローバル変数、ローカルスコープを持つ変数のことをローカル変数

# グローバルスコープで変数aを定義
a = 10

def example_function():
    # ローカルスコープで変数aを定義
    a = 20
    print(f"Inside function, local a: {a}")  # ローカル変数aの値を表示

example_function()  # 関数を実行
print(f"Outside function, global a: {a}")  # グローバル変数aの値を表示

仮引数のスコープ──型に要注意

  • イミュータブル型(整数、文字列、タプルなど): 関数内で仮引数の値を変更しても、元の変数には影響しない。仮引数のスコープ内での変更はローカルなもの。
def modify_value(x):
    print(f"Before modification: {x}") # Before modification: 10
    x = 20  # 変数xに新しい値を代入
    print(f"After modification: {x}")  # After modification: 20

a = 10
modify_value(a)
print(f"Outside function: {a}")        # Outside function: 10
  • ミュータブル型(リスト、辞書、セットなど): 関数内で仮引数のオブジェクトを変更すると、元のオブジェクトにも影響を与える。関数内での変更はグローバルな影響を与える可能性があるため、注意が必要。
def modify_list(lst):
    print(f"Before modification: {lst}")    # Before modification: [1, 2, 3]
    lst.append(4)  # リストに新しい要素を追加
    print(f"After modification: {lst}")     # After modification: [1, 2, 3, 4]

my_list = [1, 2, 3]
modify_list(my_list)
print(f"Outside function: {my_list}")       # Outside function: [1, 2, 3, 4]

関数内でグローバル変数を利用するーglobal/nonlocal

globalを使うと、関数内でグローバル変数を参照または更新できる

x = 10  # グローバル変数

def update_global():
    global x  # グローバル変数を参照
    print(f"Before update: {x}")
    x = 20  # グローバル変数を更新
    print(f"After update: {x}")

update_global()
print(f"Outside function: {x}")

nonlocalを使うと、ネストされた関数のローカル変数を参照または更新できる

def outer_function():
    x = 10  # 外側関数のローカル変数

    def inner_function():
        nonlocal x  # 外側関数の変数を参照
        print(f"Before update: {x}")
        x = 20  # 外側関数のローカル変数を更新
        print(f"After update: {x}")

    inner_function()
    print(f"Outside inner_function: {x}")

outer_function()

ブロックレベルのスコープ

Pythonでは、ブロックレベルのスコープはない。これは、C言語やJavaのような言語とは異なる重要な特徴

if True:
    x = 10  # `if`ブロック内で変数を定義
print(x)    # ブロック外でも変数`x`は利用可能

引数の様々な記法

引数の既定値

def greet(name="Guest"):
    print(f"Hello, {name}!")

# 引数を渡した場合
greet("Alice")  # Hello, Alice!

# 引数を渡さなかった場合
greet()         # Hello, Guest!

関数の既定値は、定義時点で一度だけ評価されるのが基本なので、既定値としてリスト辞書などのミュータブルなオブジェクトを使用する際は要注意
関数が複数回呼び出されると、前回の呼び出しでの変更が次回に影響する場合がある

def append_to_list(value, my_list=[]):
    my_list.append(value)
    return my_list

print(append_to_list(1))  # [1]
print(append_to_list(2))  # [1, 2]

キーワード引数

関数を呼び出す際に「引数名=値」の形式で指定する方法

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

# キーワード引数を使用
greet(name="Alice", greeting="Hi")  # Hi, Alice!

# 順序を入れ替えても動作する
greet(greeting="Good morning", name="Bob")  # Good morning, Bob

# 省略可能な引数(既定値を使用)
greet(name="Charlie")  # Hello, Charlie!

位置引数キーワード引数を強制的に使い分ける

def introduce(name, /, *, age, city="Unknown"):
    """
    名前を位置引数で、年齢と都市をキーワード引数で受け取り、自己紹介を出力する関数。
    
    Args:
        name (str): 名前(位置引数としてのみ指定可能)
        age (int): 年齢(必須のキーワード引数)
        city (str): 都市(任意のキーワード引数、デフォルトは "Unknown")
    """
    print(f"My name is {name}, I'm {age} years old, and I live in {city}.")

# 使用例
introduce("Alice", age=25, city="Tokyo")  # 正常
introduce("Bob", age=30)                 # cityを省略可能
構文 効果 サポートされるバージョン
/ それ以前の引数を位置引数としてのみ受け取る Python 3.8以降
* それ以降の引数をキーワード引数として受け取る Python 3.0以降

可変長引数の関数

引数の数が不定の場合に、可変長引数を利用できる
タプルとして受け取る: *args
辞書として受け取る: **kwargs

def demo_function(*args, **kwargs):
    print("位置引数(タプル):", args)       # 位置引数(タプル): (1, 2, 3)
    print("キーワード引数(辞書):", kwargs)  # キーワード引数(辞書): {'name': 'Alice', 'age': 30}

# 使用例
demo_function(1, 2, 3, name="Alice", age=30)

「*」「**」による引数の展開

関数呼び出し時に *** を使って、リストや辞書を個別の引数として展開できる

def add_three_numbers(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
result = add_three_numbers(*numbers)  # リストを展開して渡す
print(result)

関数呼び出しと戻り値

複数の戻り値

関数から複数の値を返すことができ、タプルを使って直感的に複数のデータをやり取りできる。

def calculate(a, b):
    sum_result = a + b
    diff_result = a - b
    # sum_resultとdiff_resultをタプルとして返す
    return sum_result, diff_result  # 複数の値を返す(タプル)

# 戻り値はタプル(15, 5)となり、それをsum_valueとdiff_valueに展開
sum_value, diff_value = calculate(10, 5)

# 合計の値を表示
print("合計:", sum_value) # 合計: 15
# 差の値を表示
print("差:", diff_value)  # 差: 5

戻り値を名前付きタプルで返すほうがわかりやすい

from collections import namedtuple


def calculate(a, b):
    # 名前付きタプル「Result」を定義。フィールド名を 'sum' と 'difference' にする
    Result = namedtuple('Result', ['sum', 'difference'])

    # sumとdifferenceを計算
    sum_result = a + b
    diff_result = a - b
    # 名前付きタプルとして返す
    return Result(sum=sum_result, difference=diff_result)

# 関数の戻り値を名前付きタプルとして受け取る
result = calculate(10, 5)

# 名前付きタプルのフィールドを使ってアクセス
print(f"合計: {result.sum}")
print(f"差: {result.difference}")

再帰関数

関数が自分自身を呼び出す形式の関数。再帰を使うことで、複雑な問題を簡潔に表現することができる。
再帰関数を正しく使うためには、終了条件(ベースケース) を明確に定義する必要があります

# 例: 階乗(n!)の計算
def factorial(n):
    # ベースケース: 0! = 1
    if n == 0:
        return 1
    else:
        # 再帰呼び出し: n! = n * (n-1)!
        return n * factorial(n - 1)

# 使用例
result = factorial(5)
print(result)  # 出力: 120 (5! = 5 * 4 * 3 * 2 * 1)

高階関数

引数として他の関数を取る、または結果として関数を返す関数のこと。関数が他の関数を操作することで、プログラムの柔軟性や再利用性が向上する。

# 高階関数の例: 関数を引数として受け取る
def apply_function(f, data):
    return [f(x) for x in data]  # dataの各要素にfを適用

# 使用例
def square(x):
    return x * x

numbers = [1, 2, 3, 4]
result = apply_function(square, numbers)
print(result)  # 出力: [1, 4, 9, 16]

無名関数(ラムダ式)

名前を持たない関数で、lambda キーワードを使って定義する。無名関数は通常、簡単な処理を行うために使われ、関数を一時的に定義するために便利

# map()と無名関数を使ってリストの各要素を2倍にする
numbers = [1, 2, 3, 4]
doubled = list(map(lambda x: x * 2, numbers))
print(doubled)  # 出力: [2, 4, 6, 8]

参考

https://amzn.to/41RlbuT

Discussion