Pythonで関数を定義するには、defキーワードを使います。しかし、引数の書き方や戻り値の返し方など、具体的な構文を把握できていないと、思い通りのコードが書けずに悩むことも多いです。
引数なしの単純な関数から、引数を受け取る関数、戻り値を返す関数まで、Pythonの関数定義には覚えるべき基本パターンがいくつかあります。これらを理解しておくと、コードの再利用性が高まり、より読みやすいプログラムを書けるようです。
この記事では、Pythonのdef文を使った関数の書き方を基本から解説します。引数・戻り値の応用的な書き方や型ヒントを活用したチーム開発向けのコードスタイルまで、実践で通用する知識を順を追って説明していきます。
Pythonのdefで関数を定義する基本的な書き方
Pythonで関数を定義するには、def文を使います。def文とは、Pythonにおいて関数定義を導くキーワードで、関数名と丸括弧で囲んだ仮引数リストに続いてコロンとインデントされた処理ブロックを記述します。
関数を一度定義しておくと、同じ処理を何度でも呼び出して再利用できます。基本の書き方として、以下の3つを解説します。
- 引数なしの関数を定義する
- 引数付きの関数を定義する
- returnで戻り値を返す
まずはシンプルな構文から順に確認していきましょう。
引数なしの関数を定義する
引数なしの関数は、定義した関数名を呼び出すだけで、毎回同じ処理を実行したいときに使います。引数とは、関数に渡す値のことで、引数なしの場合は呼び出し時に何も渡す必要がありません。
以下は、挨拶文を表示する引数なしの関数の例です。
def greet():
print("こんにちは!")
# 関数を呼び出す
greet()
# 出力: こんにちは!
def文の後に関数名を記述し、コロン(:)に続けてインデントした行に処理を書きます。インデントとは、行の先頭に空白を入れてコードのブロックを示す記法で、PEP 8ではスペース4つを推奨しています。
引数なしの関数を定義する際のポイントは、以下の通りです。
- 関数名の後に必ず
()を記述する - コロンの後に処理をインデントして記述する(1行に収まる場合はコロンの後に続けて書くことも可)
- 関数を呼び出す際も
関数名()の形式で記述する
引数なしの関数は、ログの出力や初期化処理など、毎回同じ動作を行う場面で役立ちます。
引数付きの関数を定義する
引数付きの関数は、呼び出す際に値を渡すことで、その値に応じた処理を行う関数です。同じ処理でも入力によって結果を変えたい場合に使います。
以下は、名前を受け取って挨拶文を表示する関数の例です。
def greet(name):
print(f"こんにちは、{name}さん!")
greet("田中")
# 出力: こんにちは、田中さん!
greet("佐藤")
# 出力: こんにちは、佐藤さん!
関数名の後の()内に仮引数名を記述します。仮引数とは、関数定義時に宣言する引数の名前のことで、呼び出し側から渡す実引数と区別されます。
仮引数は複数指定することもでき、その場合はカンマで区切ります。
以下は、2つの数値を受け取って合計を表示する関数の例です。位置引数として渡す場合は定義した仮引数の順序に合わせて実引数を渡す必要があり、キーワード引数(add(b=5, a=3)のように引数名を指定して渡す方法)については後述します。
def add(a, b):
print(a + b)
add(3, 5)
# 出力: 8
# キーワード引数として渡す場合は順序を問わず指定できる
add(b=5, a=3)
# 出力: 8
仮引数にはわかりやすい名前をつけることで、コードの可読性が向上します。
returnで戻り値を返す
戻り値とは、関数が処理の結果として呼び出し元に返す値のことです。return文を使うことによって、関数の外でも処理結果を利用できるようです。
以下は、2つの数値を受け取って合計値を返す関数の例です。
def add(a, b):
return a + b
result = add(3, 5)
print(result)
# 出力: 8
return文に続いて返したい値や式を記述します。returnが実行されると、その時点で関数の処理が終了し、値が呼び出し元に渡されます。
print関数で出力するだけの関数と、returnで値を返す関数の違いは押さえておきましょう。以下の表に主な特徴をまとめます。
| 種類 | 特徴 | 主な用途 |
|---|---|---|
| printのみの関数 | 結果を画面に表示するだけで、呼び出し元では値を使えない | ログ出力、デバッグ |
| returnを使う関数 | 呼び出し元で戻り値を変数に代入して利用できる | 計算結果の再利用、処理の組み合わせ |
関数の処理結果を別の処理に渡したい場合は、returnを使う方針にすると、コードの柔軟性が高まります。returnを記述しない関数は、Pythonでは自動的にNoneを返します。
Pythonのdefで関数の引数と戻り値を応用する書き方
Pythonのdef文では、基本的な引数と戻り値の使い方に加えて、より柔軟な関数の定義方法が用意されています。以下の4つの応用テクニックは、必要な場面に応じて使い分けるものです。
- デフォルト引数を設定する
- 可変長引数(*argsと**kwargs)を使う
- 複数の戻り値をタプルで返す
- 型ヒントで引数と戻り値の型を明示する
それぞれの技法には用途と注意点があり、使い方を誤るとバグの原因になることもあります。特に*argsや**kwargsは便利な一方で、多用するとコードが読みにくくなるため、通常の引数で対応できる場合は無理に使わないことを推奨します。
それでは各項目について、詳しく解説していきます。
デフォルト引数を設定する
デフォルト引数とは、関数を呼び出す際に引数を省略したときに使われる初期値のことです。仮引数名に続けて「= 値」と記述することで設定できます。
デフォルト値は関数定義時に一度だけ評価される点が、押さえておくべき仕様です。
def greet(name, greeting="こんにちは"):
return f"{greeting}、{name}さん!"
print(greet("山田")) # こんにちは、山田さん!
print(greet("山田", "おはよう")) # おはよう、山田さん!
上記のコードでは、greetingにデフォルト値を設定しているため、1つの引数だけで呼び出すことも、2つの引数を指定することもできます。
デフォルト引数を使う際には、ミュータブル(変更可能)なオブジェクトを初期値に指定することは避けるべきです。リストや辞書をデフォルト値に指定すると、そのオブジェクトは関数の定義時に1度だけ生成され、呼び出しをまたいで共有されてしまいます。
# NG: リストをデフォルト引数に指定した場合
def append_item_ng(item, items=[]):
items.append(item)
return items
print(append_item_ng(1)) # [1]
print(append_item_ng(2)) # [1, 2] ← 前の呼び出しの結果が残っている
# OK: Noneを使った書き方
def append_item_ok(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(append_item_ok(1)) # [1]
print(append_item_ok(2)) # [2] ← 毎回新しいリストが生成される
多くの場合は初期値にNoneを指定し、関数の内部でNoneチェックを行って新しいオブジェクトを生成するパターンを使います。この書き方はPythonの慣用的なイディオムとして広く使われており、ほとんどのケースはこのパターンで対応できます。
Python公式ドキュメントでは、デフォルト引数の評価タイミングについて以下のように説明しています。
Default parameter values are evaluated from left to right when the function definition is executed.
出典:Python公式ドキュメント - 8.7. Function definitions
このように、デフォルト値は関数定義の実行時(呼び出し時ではなく定義時)に一度だけ評価されます。ミュータブルなオブジェクトでは特に注意が必要です。
可変長引数(*argsと**kwargs)を使う
可変長引数とは、呼び出し時に渡す引数の個数を固定せず、任意の数の引数を受け取る仕組みのことです。*argsは位置引数を、**kwargsはキーワード引数を可変長で受け取ります。
# *args: 複数の位置引数をタプルとして受け取る
def sum_all(*args):
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100
# **kwargs: 複数のキーワード引数を辞書として受け取る
def show_profile(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
show_profile(name="山田", age=30, city="東京")
# name: 山田
# age: 30
# city: 東京
*argsを指定すると、渡された位置引数がタプルとして関数内で利用できます。**kwargsを指定すると、キーワード引数が辞書として受け取られます。
両方を同時に定義する場合は、引数の順序に決まりがあります。引数の順序は「通常の引数 → *args → **kwargs」が基本構成です。
なお、*argsの後に通常の引数を置くとキーワード専用引数(呼び出し時に必ずキーワード形式で渡す必要がある引数)にもなりますが、以下のサンプルコードはシンプルな3段階構成(通常の引数・*args・**kwargs)で示しています。
# 通常の引数、*args、**kwargsを組み合わせる
def mixed(required, *args, **kwargs):
print(f"必須: {required}")
print(f"追加の位置引数: {args}")
print(f"キーワード引数: {kwargs}")
mixed("必須値", 1, 2, 3, option="有効", mode="詳細")
# 必須: 必須値
# 追加の位置引数: (1, 2, 3)
# キーワード引数: {'option': '有効', 'mode': '詳細'}
引数名のargsとkwargsは慣習的な名前であり、*paramsや**optionsのように任意の名前を使うことも可能です。ただし、*args/**kwargsという名前がPythonコミュニティで広く使われているため、読みやすさの観点からもこの慣習に従うことを推奨します。
複数の戻り値をタプルで返す
Pythonのreturn文では、カンマ区切りで複数の値を記述することによって、複数の値を一度に返すことができます。このとき、返される値はタプルにまとめられます。
# 複数の値をカンマ区切りで返す
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(f"最小値: {low}") # 最小値: 1
print(f"最大値: {high}") # 最大値: 9
# 受け取り側でタプルとして受け取ることもできる
result = min_max([10, 20, 30])
print(result) # (10, 30)
print(type(result)) # <class 'tuple'>
戻り値は自動的にタプルにパックされるため、受け取り側ではlow, high = min_max(...)のようにアンパック(複数の変数に分解する操作)して受け取ることが一般的です。
タプルで返す方法は、Pythonで少数の複数戻り値を扱う際によく使われるパターンです。関数の戻り値として渡す組み合わせに意味がある場合(座標、最小/最大値、成功/失敗とメッセージなど)に有効で、コードの可読性を高める効果があります。
なお、項目数が多い場合や意味付けが必要な場合は、NamedTupleやdataclassなどの利用も検討してください。
型ヒントで引数と戻り値の型を明示する
型ヒントとは、引数や戻り値に期待する型をコード上に明記する注釈のことです。実行時に型チェックを強制するのではなく、IDEの補完機能やmypyなどの静的型チェックツール、ドキュメント生成に利用されます。
Python 3.5以降で利用でき、引数名の後に「: 型」と記述し、戻り値の型はアロー「->」の後に記述します。
バージョンによって使える記法が異なるため、開発環境に合わせて選択します。list[float]やdict[str, int]のように組み込み型を直接使う記法はPython 3.9以降、str | intのようなUnion記法の簡略化はPython 3.10以降で利用できます。
Python 3.8以前ではtyping.List[float]やUnion[str, int]と記述する必要があります。
# 型ヒントを使った関数の定義(Python 3.5以降)
def greet(name: str, count: int = 1) -> str:
return f"こんにちは、{name}さん!" * count
# list[float] はPython 3.9以降で使用可能
def calculate_average(numbers: list[float]) -> float:
if not numbers:
return 0.0
return sum(numbers) / len(numbers)
result: str = greet("山田", 2)
print(result) # こんにちは、山田さん!こんにちは、山田さん!
avg: float = calculate_average([1.0, 2.0, 3.0])
print(avg) # 2.0
Python公式ドキュメントでは、型ヒントの位置づけについて以下のように説明しています。
The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.
出典:Python公式ドキュメント - typing — Support for type hints
チーム開発ではPEP 484および後続のPEP群(PEP 526・585・604など)に基づく型ヒントを積極的に活用することによって、コードの意図を明確に伝えられます。
Pythonのdefの書き方に関するよくある質問
デフォルト引数にリストを指定すると何が起きますか?
デフォルト引数にリストや辞書などのミュータブルなオブジェクトを指定すると、呼び出しをまたいでオブジェクトが共有され、バグの原因となります。回避策として初期値にNoneを指定し、関数内でNoneチェックして新しいオブジェクトを生成するパターンを使ってください(詳細は「デフォルト引数を設定する」を参照)。
defとlambdaはどちらを使うべきですか?
lambdaは単一の式のみを本体として持つ無名関数で、sorted()のkey引数など関数オブジェクトを一時的に渡す場面で適しています。一方、複数行の処理やdocstring、複雑な条件分岐が必要な場合はdefを使います。
判断基準として、処理が単一の式で表現でき再利用しないならlambda、それ以外はdefを選んでください。チーム開発では型ヒントやdocstringを付けられるdefの方が保守性が高いため、迷った場合はdefを優先することを推奨します。
docstringはどのスタイルで書けばよいですか?
Pythonのdocstring規約としてはPEP 257が基準となっており、実務ではGoogle Style、NumPy Style、reStructuredText(Sphinxデフォルト)の3種類がよく使われます。どのスタイルを選ぶかは、参加するプロジェクトやチームの規約に従うことが最優先です。
チームや既存プロジェクトへの参加時はすでに採用されているスタイルに合わせてください。各スタイルは基本的に関数の目的・引数・戻り値・例外を網羅する形式になっており、これらを記述しておくとドキュメント自動生成ツール(Sphinx等)での活用やmypyなどの型チェックに役立ちます。
※上記コンテンツの内容やソースコードはAIで確認・デバッグしておりますが、間違いやエラー、脆弱性などがある場合は、コメントよりご報告いただけますと幸いです。
ITやプログラミングに関するコラム
PythonをWebで実行する方法
共通テスト「情報Ⅰ」2年目で変わる、日本の教育と学び方
gitでブランチ(branch)を切り替える方法
git cloneでブランチを指定する方法
64GBのメモリが必要な人・不要な人の特徴
PCを再起動するコマンド一覧
CapsLock以外で大文字になる原因【Windows編】
パソコンで大文字になるのを解除する方法
面白いAIの活用事例を業界別に紹介
Gitでcommit(コミット)を取り消す方法
ITやプログラミングに関するニュース
サイボウズがkintone AIを正式提供、β版から約1年を経てクレジット制を導入
ロゼッタのラクヤクAIがCSRドラフト作成期間を90%以上短縮、従来4週間を約2日に
AI CROSSが不動産業界向け生成AI伴走支援を開始、アスコットの業務AI実装を実践サポート
日本情報クリエイトが「オーナー提案AIロボⅡ」売買査定を刷新、月1万円からW査定が回数無制限に
Wur株式会社がAI新規事業診断サービス「MVP事業診断レポート」をリリース、12の質問で事業構想を約10分で分析
バトンズがM&A専門家向け「AI概要書」β版を提供開始、企業概要書のドラフトを最速3分で自動生成
SCSKが観光DXサービス「Connexia」を開発、首里城公園でNFT活用の周遊促進が始動
Verdent AI発表、エンジニア不要でソフトウェアを構築する「AIエンジニアリングチーム」が登場
ゼネラルBREXAテクノロジーが外食・小売向けAIサービス「aimana」を開発、店長の意思決定をデータで支援
田中組がKencopa工程AIエージェント製品版を先行利用開始、建設現場の工程管理属人化を解消へ
