メインコンテンツへスキップ
Lesson3 / 8

デフォルト引数

目次

1. このレッスンで学ぶこと

  • デフォルト引数とは何か
  • デフォルト引数の定義方法
  • デフォルト引数の使い所
  • デフォルト引数の注意点

2. デフォルト引数とは

デフォルト引数は、関数定義時に引数に初期値を設定し、呼び出し時に省略できるようにする機能です。

構成要素

要素説明
デフォルト値引数の初期値tax_rate=0.1
必須引数省略できない引数price
オプション引数省略可能な引数tax_rate=0.1
位置必須引数の後に配置def func(a, b=10)

主な特徴

  • 引数を省略可能にできる
  • よく使う値を初期値として設定
  • 必須引数の後に配置する
  • 関数の使いやすさが向上する

シンプルな例

Python
# デフォルト引数を持つ関数
def greet(name, greeting="こんにちは"):
    print(f"{greeting}{name}さん")

# デフォルト値を使う
greet("太郎")

# デフォルト値を上書き
greet("花子", "おはよう")

実行結果:

こんにちは、太郎さん
おはよう、花子さん

3. なぜデフォルト引数が必要か?

関数を呼び出すとき、毎回同じ値を渡すのは面倒です。

Python
# 毎回税率を指定するのは面倒
calculate_total(1000, 0.1)
calculate_total(2000, 0.1)
calculate_total(500, 0.1)

# デフォルト値を使えば省略できる
calculate_total(1000)  # 税率0.1が自動的に使われる
calculate_total(2000)
calculate_total(500)

デフォルト引数を使うことで、関数が使いやすくなります。

💡 豆知識: デフォルト引数は「オプション引数」とも呼ばれ、関数を柔軟にする重要な機能です。多くのPython標準ライブラリの関数もデフォルト引数を活用しています。例えば、print()関数のsependなどがデフォルト引数です。


4. 複数のデフォルト引数

Python
def show_product(name, price=0, stock=0, category="未分類"):
    print(f"商品名: {name}")
    print(f"  価格: {price}円")
    print(f"  在庫: {stock}個")
    print(f"  カテゴリ: {category}")

# 必須引数のみ
show_product("りんご")
print()

# 一部を指定
show_product("バナナ", 150)
print()

# 全部指定
show_product("オレンジ", 200, 10, "果物")

実行結果:

商品名: りんご
  価格: 0円
  在庫: 0個
  カテゴリ: 未分類

商品名: バナナ
  価格: 150円
  在庫: 0個
  カテゴリ: 未分類

商品名: オレンジ
  価格: 200円
  在庫: 10個
  カテゴリ: 果物

5. デフォルト引数の実用例

例1: 消費税計算

Python
def calculate_price(base_price, tax_rate=0.1, discount_rate=0):
    """商品価格を計算"""
    # 割引適用
    discounted = base_price * (1 - discount_rate)
    # 税込
    tax = int(discounted * tax_rate)
    total = int(discounted + tax)
    return total

# 通常価格(税込)
price1 = calculate_price(1000)
print(f"通常: {price1}円")

# 税率を変更
price2 = calculate_price(1000, 0.08)
print(f"軽減税率: {price2}円")

# 割引適用
price3 = calculate_price(1000, discount_rate=0.2)
print(f"20%オフ: {price3}円")

# 税率と割引を両方指定
price4 = calculate_price(1000, 0.1, 0.3)
print(f"30%オフ+税込: {price4}円")

実行結果:

通常: 1100円
軽減税率: 1080円
20%オフ: 880円
30%オフ+税込: 770円

例2: ログ出力関数

Python
def log_message(message, level="INFO", timestamp=True):
    """ログメッセージを出力"""
    if timestamp:
        time_str = "2024-01-20 10:00:00"
        print(f"[{time_str}] [{level}] {message}")
    else:
        print(f"[{level}] {message}")

# デフォルト設定(INFO、タイムスタンプあり)
log_message("処理を開始します")

# レベルを変更
log_message("警告が発生しました", "WARNING")

# エラーログ
log_message("エラーが発生しました", "ERROR")

# タイムスタンプなし
log_message("シンプルなログ", timestamp=False)

実行結果:

[2024-01-20 10:00:00] [INFO] 処理を開始します
[2024-01-20 10:00:00] [WARNING] 警告が発生しました
[2024-01-20 10:00:00] [ERROR] エラーが発生しました
[INFO] シンプルなログ

例3: データのフォーマット

Python
def format_number(number, width=10, fill_char=" ", align="right"):
    """数値を整形して表示"""
    num_str = str(number)

    if align == "right":
        result = num_str.rjust(width, fill_char)
    elif align == "left":
        result = num_str.ljust(width, fill_char)
    elif align == "center":
        result = num_str.center(width, fill_char)
    else:
        result = num_str

    return result

# デフォルト(右寄せ、幅10、スペース埋め)
print(f"|{format_number(123)}|")

# 幅を変更
print(f"|{format_number(123, 15)}|")

# ゼロ埋め
print(f"|{format_number(123, 8, '0')}|")

# 左寄せ
print(f"|{format_number(123, 10, align='left')}|")

# 中央寄せ、アスタリスク埋め
print(f"|{format_number(123, 12, '*', 'center')}|")

実行結果:

|       123|
|            123|
|00000123|
|123       |
|****123*****|

6. デフォルト引数の位置

正しい順序

機能: デフォルト引数は必須引数の後に配置します。

書き方:

Python
def 関数名(必須引数1, 必須引数2, デフォルト引数1=1, デフォルト引数2=2):
    処理

用途: 文法的に正しい関数定義

注意点: 必須引数が先、デフォルト引数が後

Python
# 正しい例
def create_user(name, email, age=0, country="Japan"):
    return {
        "name": name,
        "email": email,
        "age": age,
        "country": country
    }

user1 = create_user("太郎", "taro@example.com")
print(user1)

user2 = create_user("花子", "hanako@example.com", 25, "USA")
print(user2)

# 間違った例(エラー)
# def wrong_function(name="太郎", email):  # SyntaxError!
#     pass

実行結果:

{'name': '太郎', 'email': 'taro@example.com', 'age': 0, 'country': 'Japan'}
{'name': '花子', 'email': 'hanako@example.com', 'age': 25, 'country': 'USA'}

7. デフォルト引数の注意点

注意点1: ミュータブルなデフォルト値

悪い例:

Python
def add_item(item, items=[]):  # 危険!
    items.append(item)
    return items

# 予期しない動作
list1 = add_item("apple")
print(f"リスト1: {list1}")

list2 = add_item("banana")
print(f"リスト2: {list2}")  # appleも含まれている!

実行結果:

リスト1: ['apple']
リスト2: ['apple', 'banana']

良い例:

Python
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

# 正しい動作
list1 = add_item("apple")
print(f"リスト1: {list1}")

list2 = add_item("banana")
print(f"リスト2: {list2}")

実行結果:

リスト1: ['apple']
リスト2: ['banana']

注意点2: デフォルト値は定義時に評価される

Python
# 現在時刻を返す関数(間違った例)
import time

# 間違い: 定義時に1回だけ評価される
def log_with_time_wrong(message, timestamp=time.time()):
    print(f"[{timestamp}] {message}")

log_with_time_wrong("メッセージ1")
time.sleep(1)
log_with_time_wrong("メッセージ2")  # タイムスタンプが同じ!

print()

# 正しい: 呼び出し時に評価
def log_with_time_correct(message, timestamp=None):
    if timestamp is None:
        timestamp = time.time()
    print(f"[{timestamp}] {message}")

log_with_time_correct("メッセージ1")
time.sleep(1)
log_with_time_correct("メッセージ2")  # タイムスタンプが異なる

8. 具体例

例1: 設定管理

Python
def create_config(app_name, version="1.0.0", debug=False,
                  port=8000, host="localhost"):
    """アプリケーション設定を作成"""
    config = {
        "app_name": app_name,
        "version": version,
        "debug": debug,
        "server": {
            "host": host,
            "port": port
        }
    }
    return config

# 最小限の設定
config1 = create_config("MyApp")
print("=== 開発環境 ===")
for key, value in config1.items():
    print(f"{key}: {value}")

print()

# 本番環境の設定
config2 = create_config("MyApp", version="2.0.0",
                        debug=False, host="0.0.0.0", port=80)
print("=== 本番環境 ===")
for key, value in config2.items():
    print(f"{key}: {value}")

実行結果:

=== 開発環境 ===
app_name: MyApp
version: 1.0.0
debug: False
server: {'host': 'localhost', 'port': 8000}

=== 本番環境 ===
app_name: MyApp
version: 2.0.0
debug: False
server: {'host': '0.0.0.0', 'port': 80}

例2: データベース接続

Python
def connect_database(database, host="localhost", port=5432,
                     user="admin", password="", timeout=30):
    """データベースに接続(シミュレーション)"""
    print(f"データベース接続:")
    print(f"  ホスト: {host}:{port}")
    print(f"  データベース: {database}")
    print(f"  ユーザー: {user}")
    print(f"  タイムアウト: {timeout}秒")

    # 実際の接続処理(省略)
    return f"接続成功: {database}"

# ローカル開発環境
print("=== ローカル環境 ===")
result1 = connect_database("dev_db")
print(f"{result1}\n")

# 本番環境
print("=== 本番環境 ===")
result2 = connect_database("prod_db",
                          host="db.example.com",
                          port=3306,
                          user="prod_user",
                          password="secret123",
                          timeout=60)
print(f"{result2}")

実行結果:

=== ローカル環境 ===
データベース接続:
  ホスト: localhost:5432
  データベース: dev_db
  ユーザー: admin
  タイムアウト: 30秒
接続成功: dev_db

=== 本番環境 ===
データベース接続:
  ホスト: db.example.com:3306
  データベース: prod_db
  ユーザー: prod_user
  タイムアウト: 60秒
接続成功: prod_db

例3: レポート生成

Python
def generate_report(title, data, format="text",
                   include_timestamp=True, page_size=20):
    """レポートを生成"""
    print("=" * 50)
    print(f"レポート: {title}")

    if include_timestamp:
        print(f"作成日時: 2024-01-20 10:00:00")

    print(f"形式: {format}")
    print(f"ページサイズ: {page_size}")
    print("=" * 50)

    # データ表示
    for i, item in enumerate(data, 1):
        print(f"{i}. {item}")
        if i >= page_size:
            print(f"... 他 {len(data) - page_size} 件")
            break

    print("=" * 50)

# シンプルなレポート
sales_data = ["商品A: 100個", "商品B: 85個", "商品C: 120個"]
generate_report("売上レポート", sales_data)

print()

# 詳細なレポート
detailed_data = [f"データ{i}" for i in range(1, 51)]
generate_report("詳細レポート", detailed_data,
               format="PDF", page_size=10)

実行結果:

==================================================
レポート: 売上レポート
作成日時: 2024-01-20 10:00:00
形式: text
ページサイズ: 20
==================================================
1. 商品A: 100個
2. 商品B: 85個
3. 商品C: 120個
==================================================

==================================================
レポート: 詳細レポート
作成日時: 2024-01-20 10:00:00
形式: PDF
ページサイズ: 10
==================================================
1. データ1
2. データ2
3. データ3
4. データ4
5. データ5
6. データ6
7. データ7
8. データ8
9. データ9
10. データ10
... 他 40 件
==================================================

9. 練習問題

問題1(基礎)⭐☆☆

名前を必須引数として受け取り、挨拶の言葉をデフォルト引数(初期値は「こんにちは」)として受け取る関数 greet を作成してください。関数は「〇〇、△△さん!」という形式で挨拶を表示します。作成した関数を、デフォルト値を使う場合と上書きする場合の両方で呼び出してください。

💡 ヒント
  1. def greet(name, greeting="こんにちは"): で関数を定義
  2. f-stringを使って挨拶文を作成
  3. print() で表示
  4. greet("太郎") でデフォルト値を使用
  5. greet("花子", "おはよう") でデフォルト値を上書き
✅ 解答例
Python
def greet(name, greeting="こんにちは"):
    print(f"{greeting}{name}さん!")

# デフォルト値を使う
greet("太郎")

# デフォルト値を上書き
greet("花子", "おはよう")
greet("次郎", "こんばんは")

実行結果:

こんにちは、太郎さん!
おはよう、花子さん!
こんばんは、次郎さん!

解説: デフォルト引数 greeting="こんにちは" により、greet("太郎") のように第2引数を省略すると自動的に「こんにちは」が使われます。greet("花子", "おはよう") のように値を指定すると、デフォルト値が上書きされます。


問題2(基礎)⭐☆☆

長方形の幅を必須引数、高さをデフォルト引数(初期値は 10)として受け取り、面積を戻り値として返す関数 calculate_area を作成してください。幅が 5 のときと、幅が 8、高さが 6 のときの面積をそれぞれ計算して表示してください。

💡 ヒント
  1. def calculate_area(width, height=10): で関数を定義
  2. area = width * height で面積を計算
  3. return area で結果を返す
  4. calculate_area(5) でデフォルト値を使用
  5. calculate_area(8, 6) でデフォルト値を上書き
✅ 解答例
Python
def calculate_area(width, height=10):
    area = width * height
    return area

# デフォルト値を使う場合(高さ10)
area1 = calculate_area(5)
print(f"幅5、高さ10の面積: {area1}")

# デフォルト値を上書きする場合
area2 = calculate_area(8, 6)
print(f"幅8、高さ6の面積: {area2}")

実行結果:

幅5、高さ10の面積: 50
幅8、高さ6の面積: 48

解説: height=10 というデフォルト引数により、高さを省略すると自動的に 10 が使われます。calculate_area(5)5 × 10 = 50 を、calculate_area(8, 6)8 × 6 = 48 を計算します。


問題3(応用)⭐⭐☆

商品名を必須引数、単価をデフォルト引数(初期値 100)、数量をデフォルト引数(初期値 1)、消費税率をデフォルト引数(初期値 0.1)として受け取る関数 calculate_product_total を作成してください。この関数は小計、消費税、合計を含む辞書を返します。以下の3つのパターンで関数を呼び出してください:

  1. 商品名のみ指定(「りんご」)
  2. 商品名と単価を指定(「バナナ」、単価 150
  3. 商品名、単価、数量を指定(「オレンジ」、単価 200、数量 3
💡 ヒント
  1. def calculate_product_total(name, price=100, quantity=1, tax_rate=0.1): で関数を定義
  2. 小計 = 単価 × 数量
  3. 消費税 = 小計 × 消費税率(整数にする)
  4. 合計 = 小計 + 消費税
  5. 辞書で結果を返す: return {"name": name, "subtotal": subtotal, ...}
✅ 解答例
Python
def calculate_product_total(name, price=100, quantity=1, tax_rate=0.1):
    # 小計を計算
    subtotal = price * quantity

    # 消費税を計算
    tax = int(subtotal * tax_rate)

    # 合計を計算
    total = subtotal + tax

    # 結果を辞書で返す
    return {
        "name": name,
        "price": price,
        "quantity": quantity,
        "subtotal": subtotal,
        "tax": tax,
        "total": total
    }

# パターン1: 商品名のみ(すべてデフォルト値)
result1 = calculate_product_total("りんご")
print(f"{result1['name']}: 単価{result1['price']}円 × {result1['quantity']}個 = 合計{result1['total']}円")

# パターン2: 商品名と単価を指定
result2 = calculate_product_total("バナナ", 150)
print(f"{result2['name']}: 単価{result2['price']}円 × {result2['quantity']}個 = 合計{result2['total']}円")

# パターン3: 商品名、単価、数量を指定
result3 = calculate_product_total("オレンジ", 200, 3)
print(f"{result3['name']}: 単価{result3['price']}円 × {result3['quantity']}個 = 合計{result3['total']}円")

実行結果:

りんご: 単価100円 × 1個 = 合計110円
バナナ: 単価150円 × 1個 = 合計165円
オレンジ: 単価200円 × 3個 = 合計660円

解説: 複数のデフォルト引数を持つ関数の実用的な例です。デフォルト引数を使うことで、必要な引数だけを指定できます。calculate_product_total("りんご") は商品名以外すべてデフォルト値を使い、calculate_product_total("バナナ", 150) は単価だけを指定し数量と消費税率はデフォルト値を使います。戻り値を辞書にすることで、複数の計算結果を分かりやすく返すことができます。


10. まとめ

このレッスンでは、デフォルト引数の使い方と注意点を学びました。

  • デフォルト引数を使うと、呼び出し時の省略を柔軟に扱えます。
  • 引数の順序と指定方法を理解して正しく設計できます。
  • 可変オブジェクトをデフォルト値に使う際の注意点を確認しました。
  • 関数呼び出し側の負担を減らすインターフェース設計を学びました。
  • 安全なデフォルト値の選択が、予期しない不具合を防ぎます。