# Pythonの関数：def、return、引数、*argsと**kwargs、lambda、型注釈

URL: https://skillaria.top/ja/guides/python/funkcii-python

Pythonの関数は、名前を付けたコードのまとまりで、def で定義し、名前と丸かっこで呼び出し、return で結果を返します。return がなければ None が返ります。引数は順番どおりにも名前を指定しても渡せます。*args は余分な位置引数をタプルに、**kwargs は余分な名前付き引数を辞書にまとめます。lambda は1つの式だけからなる短い無名関数を作ります。

Pythonの関数は、名前の付いたコードのまとまりです。何度でも、異なる入力を渡して呼び出せます。`def` で定義し、引数で値を受け取り、`return` で結果を返します。長いスクリプトを、分かりやすくテストしやすい手順に分ける最も基本的な方法です。

## 関数の定義：def

関数の定義は `def` で始まり、関数名、丸かっこの中の引数、コロンが続きます。本体は4つのスペースでインデントします。Pythonではインデントは飾りではなく、文法の一部です。

```
def greet(name):
    """ユーザーへの挨拶を返す。"""
    return f"こんにちは、{name}さん！"

print(greet("花子"))   # こんにちは、花子さん！
```

見出しの直後に三重引用符で書いた文字列は、docstring（ドキュメント文字列）です。`help(greet)` やエディタのヒントに表示されます。関数名は、PEP 8の慣習に従ってsnake_caseで書きます。例：`add_expense`、`get_rate`。

`def greet(name):` の部分を関数のシグネチャ（署名）といいます。関数名と引数の一覧（型注釈があればそれも）から成ります。シグネチャを見れば、本体を読まなくても呼び出し方が分かります。

## Pythonのreturnの働き

`return` は関数を終了させ、呼び出し元に値を渡します。`return` が実行された後のコードは実行されません。`return` がない場合、または値なしの `return` の場合、関数は `None` を返します。

```
def area(w, h):
    w * h          # 計算はされるが、結果は捨てられる

print(area(3, 4))  # None

def area(w, h):
    return w * h

print(area(3, 4))  # 12
```

`return` を書き忘れるのは、初心者に最も多いミスの1つです。関数は動くのに `None` が返り、エラーは次の行で見つかります。複数の値を返すこともできます。実際には1つのタプルで、分解代入で受け取れます。

```
def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9])
print(low, high)   # 1 9
```

早めに `return` すると、入れ子を減らせます。まず特殊なケースを除外し、その後に本来の処理を書きます。

```
def discount(price, is_member):
    if price  limit    # 大域変数の読み取りは可能

def raise_limit():
    global limit
    limit = 2000             # global がないと、ローカル変数が新しく作られる
```

実際には `global` はあまり使わない方が良いでしょう。外部の状態を変更する関数はテストしにくくなります。値を引数で受け取り、結果を返すようにする方が確実です。

## 入れ子の関数とクロージャ

関数の中に別の関数を定義することもできます。内側の関数は、外側の関数が終わった後でも外側の変数を参照できます。これをクロージャ（閉包）といいます。こうした変数を変更するには `nonlocal` を使います。

```
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c(), c(), c())   # 1 2 3
```

クロージャは、デコレータや関数を生成するファクトリの基礎になっています。

## 関数もオブジェクト

Pythonでは、関数は普通のオブジェクトです。変数に代入でき、別の関数に渡し、関数から返し、辞書に保存できます。関数には `__name__`、`__doc__`、`__defaults__`、`__annotations__` といった属性があります。

```
def double(x):
    return x * 2

f = double
print(f(5), f.__name__)                # 10 double
print(list(map(double, [1, 2, 3])))   # [2, 4, 6]
```

## Pythonのlambda：無名関数

lambda 関数は、名前のない短い関数です。本体は1つの式だけで、その結果が自動的に返されます。`return` は書けません。

```
square = lambda x: x ** 2
print(square(4))   # 16

expenses = [("コーヒー", 250), ("タクシー", 600), ("ランチ", 450)]
expenses.sort(key=lambda e: e[1], reverse=True)
print(expenses)  # [('タクシー', 600), ('ランチ', 450), ('コーヒー', 250)]

print(list(filter(lambda n: n % 2 == 0, range(10))))  # [0, 2, 4, 6, 8]
```

Pythonのlambdaは、`sorted`、`max`、`map`、`filter` に渡す短い引数として役立ちます。上の `square` のように、lambdaを変数に代入するのはPEP 8で推奨されていません。関数に名前が必要なら `def` を使いましょう。そうすれば、トレースバックに正しい `__name__` が表示され、docstringも書けます。

|  | def | lambda |
| --- | --- | --- |

| 名前 | あり | なし（`<lambda>`） |

| 本体 | 任意の数の文 | 1つの式 |

| return | 明示的 | 暗黙的 |

| docstring、注釈 | あり | なし |

| 向いている場面 | あらゆる場面 | 短い key やコールバック |

## 型注釈：ヒントであって、検査ではない

型注釈は、パラメータと戻り値に期待される型を示します。Python自身は実行時に注釈をチェックしません。`x: int` と書かれた関数に文字列を渡しても、そのまま動きます。注釈を検査するのは、mypy、pyright、ty などの外部ツールや、実行前にエラーを表示するエディタです。

```
def add_expense(title: str, amount: float, category: str = "その他") -> dict[str, object]:
    return {"title": title, "amount": amount, "category": category}

def area(w: float, h: float) -> float:
    w * h   # mypy: Missing return statement
```

インストールせずに検査するには、`uvx mypy .` を実行します。上の例は注釈の効果を示しています。`-> float` と書いた関数で `return` を忘れると、解析ツールがすぐに見つけてくれます。

Python 3.12（PEP 695）からは、ジェネリックな関数を `TypeVar` なしで書けます。型パラメータは角かっこで指定し、型のエイリアスは `type` 文で宣言します。

```
def first[T](xs: list[T]) -> T:
    return xs[0]

type Money = int | float
```

Python 3.14（PEP 649）では、注釈が遅延評価されるようになりました。注釈は最初に参照されたときに評価されるため、後で定義されるクラスを引用符なしで書けます。`from __future__ import annotations` も不要です。

## 「渡されなかった」と「None が渡された」の区別：Python 3.15のsentinel

デフォルト値が `None` だと、「引数が渡されなかった」のと「あえて None が渡された」のを区別できません。長年、次のような独自の目印を使って解決されてきました。

```
_MISSING = object()

def get_rate(currency, default=_MISSING):
    rates = {"USD": 90.5}
    if currency in rates:
        return rates[currency]
    if default is _MISSING:
        raise KeyError(currency)
    return default
```

Python 3.15 では、組み込みの `sentinel` 関数が追加されました（PEP 661）。`MISSING = sentinel("MISSING")` と書くと、分かりやすい repr を持つ一意のマーカーが作られます。コピーしても同じものが残り、pickleでシリアライズでき、`float | MISSING` のような注釈にも使えます。古いバージョンでは、`object()` を使う方法がそのまま使えます。

## 関数でよくあるミス

- **return を忘れる** — 関数は `None` を返します。
- **かっこを忘れる** — `print(greet)` は、呼び出し結果ではなく関数オブジェクトを表示します。
- **変更可能なデフォルト値** — すべての呼び出しで同じリストが共有されます。
- **引数の数の間違い** — `TypeError: greet() missing 1 required positional argument: 'name'`。
- **組み込みの名前と衝突する** — `list` や `sum` という名前の関数は、組み込みを隠してしまいます。

## まとめ

Pythonの関数は `def` で定義し、`return` で結果を返し、引数を順番どおりにも名前を指定しても受け取れます。`*args` と `**kwargs` で柔軟性を、`/` と `*` で呼び出しの厳密さを、lambda で一度だけ使う関数の簡潔さを得られます。型注釈は、mypyと組み合わせれば実行前にエラーを見つけてくれます。講座では、この内容を実践で扱います。家計簿ツールを型注釈付きの関数に分け、mypyで検査します。

## FAQ

**引数（パラメータ）と引数（アーギュメント）はどう違いますか？**

パラメータは関数定義の中にある名前、引数は呼び出し時に渡す具体的な値です。def greet(name) の name はパラメータ、greet("花子") の "花子" は引数です。

**関数を定義する前に呼び出せますか？**

モジュールの最上位では無理です。def の行が先に実行されていないと NameError になります。ただし、別の関数の中から、その関数の定義より後に書かれた関数を呼び出すことは、その呼び出しが定義の後に行われるなら可能です。

**関数は複数の値を返せますか？**

形式的には1つの値ですが、その値をタプルにすれば複数の値を返せます。return a, b はタプルを返し、x, y = f() のように分解して受け取れます。

**型注釈は必ず書く必要がありますか？**

いいえ。注釈がなくても Python は動きます。ただし、他の人が読むコードでは、注釈があると保守が格段に楽になり、mypyやpyrightでエラーを早期に見つけられます。

**lambdaの中でifは使えますか？**

条件式なら使えます。例：lambda x: "偶数" if x % 2 == 0 else "奇数"。文、ループ、代入を lambda の中に書くことはできません。


---
Source: Skillaria.Top (https://skillaria.top)
