関数に渡す引数へ初期値を設定できると、呼び出し時に毎回細かい指定をしなくても済み、短く読みやすいコードになります。
Pythonではこれをデフォルト引数と呼び、柔軟かつ簡潔な関数設計を助けます。
本記事では、基本的な書き方から注意点、実用例までを初心者向けに丁寧に解説します。
Pythonのデフォルト引数とは
引数に初期値を設定できる仕組み
概要
デフォルト引数とは、関数定義のときに引数へ初期値を与えておき、呼び出し側で省略できるようにする仕組みです。
書式はdef 関数名(引数=初期値):
のように、引数名の右側に=
で値を指定します。
呼び出し時にその引数を渡さなければ初期値が使われ、値を渡せばその値で上書きされます。
イメージ
- 値を渡さない場合: 「既定の設定で動く」
- 値を渡す場合: 「必要な所だけ上書きする」
このように、1つの関数で多様な使い方に対応できます。
使うメリット 省略や再利用が楽
デフォルト引数を使うと、関数を呼ぶたびに繰り返し同じ値を渡す必要がなくなります。
また、関数のインターフェースが自己文書化され、どんな設定が標準なのかが署名から読み取れます。
結果として呼び出しが簡潔になり、再利用性が高まり、バグの混入も減らせます。
微調整が必要なときだけキーワード引数で上書きできるため、柔軟性も損なわれません。
Pythonのデフォルト引数の使い方
基本の書き方 def func(arg=初期値)
デフォルト引数は引数名の後ろに= 初期値
を置きます。
初期値は整数や文字列などのイミュータブル型が基本的に安全です。
# 例: 冪乗を計算する関数。指数 exp は指定しなければ 2(二乗)になります。
def power(base, exp=2):
"""base の exp 乗を返す。exp を省略すると 2(二乗)。"""
return base ** exp
# 省略時は二乗、指定時は指定の指数で計算
print(power(3)) # 3 ** 2
print(power(3, 3)) # 3 ** 3
9
27
呼び出し 省略と上書き
省略すると初期値が使われ、渡せばその値で上書きされます。
必要最低限の引数だけを指定して、使いたい時にだけ詳細を上書きするのが基本的な運用です。
def greet(name="world"):
"""name を省略したら 'world' で挨拶します。"""
return f"Hello, {name}!"
print(greet()) # 省略
print(greet("Alice")) # 上書き
Hello, world!
Hello, Alice!
複数のデフォルト引数
複数の引数へ初期値を設定できます。
キーワード引数と組み合わせると意図がより明確になります。
def make_url(domain, path="/", scheme="https"):
"""スキームとパスを省略可能にした URL 生成関数。"""
# path が "/" から始まっていなければ付け足す
if not path.startswith("/"):
path = "/" + path
return f"{scheme}://{domain}{path}"
print(make_url("example.com")) # 省略
print(make_url("example.com", "/docs")) # path 上書き
print(make_url("example.com", "docs", scheme="http")) # 複数上書き
https://example.com/
https://example.com/docs
http://example.com/docs
並びのルール 非デフォルトの後ろに置く
非デフォルト引数はデフォルト引数より前に並べる必要があります。
逆にすると構文エラーになります。
NG例
# NG: 非デフォルト引数 b がデフォルト引数 a の後ろにある
def broken(a=1, b):
return a + b
SyntaxError: non-default argument follows default argument
OK例
def ok(a, b=1):
return a + b
print(ok(10)) # b は初期値 1
print(ok(10, 5)) # b を上書き
11
15
キーワード引数と併用する
キーワード引数を使うと、位置を意識せず名前で値を渡せます。
デフォルト引数と組み合わせると、必要な部分だけを狙って上書きでき、読みやすさも向上します。
def format_name(first, last, sep=" ", order="FL"):
"""order は 'FL'(名→姓) または 'LF'(姓→名) を想定。sep は区切り文字。"""
if order == "FL":
return f"{first}{sep}{last}"
else:
return f"{last}{sep}{first}"
print(format_name("Taro", "Yamada")) # 省略: "Taro Yamada"
print(format_name("Taro", "Yamada", order="LF")) # 名前付きで順序だけ上書き
print(format_name("Taro", "Yamada", sep="・", order="LF")) # 複数を名前付きで上書き
Taro Yamada
Yamada Taro
Yamada・Taro
Pythonのデフォルト引数の注意点
ミュータブル型を初期値にしない listやdictはNG
なぜNGか
list や dict のようなミュータブル(変更可能)なオブジェクトを初期値にすると、関数定義時に1度だけ生成された同じオブジェクトが使い回されてしまい、思わぬ共有が起きます。
複数回呼び出しても前回の変更が残り続け、バグの原因になります。
NG例コード
# NG: 同じ list が全呼び出しで共有される
def append_log(message, log=[]):
"""log に message を追加して返す(意図どおりに動かない例)。"""
log.append(message)
return log
print(append_log("start"))
print(append_log("step1"))
print(append_log("step2"))
['start']
['start', 'step1']
['start', 'step1', 'step2']
意図としては毎回['stepX']
のように独立したリストを期待するかもしれませんが、実際は同じリストが使われ続けています。
Noneを使う安全パターン
ミュータブルを初期値にしたい場合は、デフォルト値にはNone
を使い、関数内で新しく作るのが定石です。
これにより毎回独立したオブジェクトになります。
OK例コード
def append_log_safe(message, log=None):
"""log が省略された場合は新しい list を作る安全な実装。"""
if log is None: # None との比較は "is" が慣用
log = [] # 毎回新しいリストを作成
log.append(message)
return log
print(append_log_safe("start")) # ['start']
print(append_log_safe("step1")) # ['step1'] 共有されない
print(append_log_safe("step2", [])) # 外から渡すことも可能
['start']
['step1']
['step2']
この「Noneを使う」パターンは、list/dict/set などミュータブル全般で有効です。
デフォルト値は定義時に一度だけ評価される
仕組み
デフォルト値は関数が定義された時に1回だけ評価され、以降は同じオブジェクトが使われ続けます。
そのため、現在時刻や乱数など「呼ぶたびに変わってほしい値」をデフォルトに書くと意図とズレます。
例: datetime.now() をデフォルトにすると固定される
from datetime import datetime
import time
def stamped(ts=datetime.now()):
"""定義時点の時刻が固定で入る例。"""
return ts
print("first :", stamped().isoformat())
time.sleep(2)
print("second:", stamped().isoformat()) # 2秒後でも同じ値
first : 2024-01-01T12:00:00.000000
second: 2024-01-01T12:00:00.000000
期待と異なる場合は、次のようにNone
を使います。
from datetime import datetime
def stamped_safe(ts=None):
"""呼び出しのたびに現在時刻を採用する安全版。"""
if ts is None:
ts = datetime.now()
return ts
まとめ表
デフォルト値の種類 | 例 | 安全性 | 理由 |
---|---|---|---|
イミュータブル | 0, 1.0, “ok”, (), frozenset() | 安全 | 共有されても変わらないため |
ミュータブル | [], {}, set() | 危険 | 呼び出し間で変更が共有される |
変化する値 | datetime.now(), random.random() | 危険 | 定義時に固定されてしまう |
基本はイミュータブルを使い、ミュータブルやその場で変わる値は None パターンで生成する、と覚えておくと安心です。
Pythonのデフォルト引数のサンプル
あいさつ関数 nameに初期値
名前を省略したら一般的な挨拶を行い、指定したらその人に挨拶する関数です。
小さな違いをデフォルト引数で吸収すると、呼び出しがスッキリします。
def greet(name="世界", polite=False):
"""
name を省略すると '世界' に挨拶します。
polite=True にすると丁寧な言い回しに変わります。
"""
if polite:
return f"こんにちは、{name}さん。"
else:
return f"やあ、{name}!"
# 省略(既定値を使用)
print(greet())
# 名前を上書き
print(greet("Alice"))
# 丁寧モードだけキーワードで上書き
print(greet("太郎", polite=True))
やあ、世界!
やあ、Alice!
こんにちは、太郎さん。
税込み計算 tax_rateに初期値
消費税率をデフォルト10%(0.1)として、税抜価格に税を加算します。
税率変更や軽減税率に対応したいときだけ上書きします。
実務での通貨計算では Decimal の使用検討も有効ですが、ここでは分かりやすさを優先して小数の丸めを使います。
def price_with_tax(price, tax_rate=0.1):
"""
price に税率 tax_rate を乗じた税込価格を返します。
小数点以下は 2 桁に丸めます(表示用途の簡易例)。
"""
total = round(price * (1 + tax_rate), 2) # 例: 1000 × 1.1 = 1100.0
return total
# 既定の税率(10%)
print(price_with_tax(1000))
# 軽減税率(8%)へ上書き
print(price_with_tax(1000, tax_rate=0.08))
# 小数価格の例
print(price_with_tax(1234.56))
1100.0
1080.0
1358.02
まとめ
デフォルト引数は、関数の使い勝手を飛躍的に高める基本テクニックです。
省略できる所は既定値で受け止め、必要な時だけキーワード引数で上書きすれば、コードは短く読みやすくなります。
ただしミュータブル型を初期値にするのは避け、Noneで受けてから生成するというルールを徹底しましょう。
さらにデフォルト値は定義時に一度だけ評価されることを理解しておけば、時刻や乱数などの落とし穴も避けられます。
今回のサンプルを土台に、自分の関数でも初期値設計を試してみてください。