関数
プログラムが大きくなるにつれて、同じロジックを複数の場所で書くことになります。関数を使えば、ロジックを一度だけ書いて名前を付け、どこでも使うことができます。一箇所を修正すれば、すべての呼び出し箇所に自動的に反映されます。
def greet(name):
return f"Hello, {name}!"
print(greet("さくら")) # "Hello, さくら!"
print(greet("ひろし")) # "Hello, ひろし!"一度書けば、どこでも使え、一箇所で修正できます。
関数の定義
def キーワードで関数定義を開始し、名前、丸括弧、コロン、そしてインデントされた本体が続きます。関数は呼び出されるまで何もしません。def で定義し、その後 () を付けて名前で呼び出します。
def say_hello():
print("Hello!")
say_hello() # 関数を呼び出すパラメータと引数
パラメータは関数が期待する入力です。丸括弧の中にリストします。関数を呼び出すと、渡した値が順番にパラメータに対応付けられます。
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("さくら", "Hello") # "Hello, さくら!"
greet("ひろし", "Hi") # "Hi, ひろし!"パラメータと引数
パラメータ は関数定義の中の名前です。引数 は関数を呼び出すときに実際に渡す値です。実際には、これらの言葉は同じ意味で使われます。ドキュメントを読むときには区別があることを意識しておきましょう。
デフォルト値
パラメータにデフォルト値を与えることができます。呼び出し側がその引数を提供しなかった場合、デフォルト値が使われます。デフォルト値のあるパラメータは、デフォルト値のないパラメータの後に来る必要があります。
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("さくら") # "Hello, さくら!"
greet("さくら", "Hi") # "Hi, さくら!"デフォルト値のあるパラメータは、デフォルト値のないパラメータの後に来る必要があります。
キーワード引数
関数を呼び出すとき、引数に名前を付けることができます。これにより、特に多くのパラメータを持つ関数では呼び出しが読みやすくなり、任意の順序で渡すことができます。
def describe_player(name, score, level):
print(f"{name} | Score: {score} | Level: {level}")
describe_player("さくら", 87, 5) # 位置
describe_player(name="さくら", level=5, score=87) # キーワード、任意の順序
describe_player("さくら", level=5, score=87) # 混合: 位置が先戻り値
return は呼び出し側に値を送り返します。return がない場合、関数は None を返します。return が実行されると、関数は直ちに終了します。そのブロック内のそれ以降のコードはスキップされます。
def add(a, b):
return a + b
result = add(3, 4) # result = 7
print(result)return はまた、関数を直ちに終了させます。そのブロック内のそれ以降のコードは実行されません。
複数の値を返す
Python ではカンマで区切ることで複数の値を返すことができます。呼び出し側はそれらをタプルとして受け取り、一行で別々の名前にアンパックできます。
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 7, 1, 9, 4])
print(low, high) # 1 9low, high = ... という構文は アンパッキング です。Python は返された各値を対応する名前に代入します。
スコープ
関数内で作成された変数は、その関数内にのみ存在します。外からは見えません。すべての関数の外で定義された変数はどこからでも見えますが、明示的な宣言なしに関数の中から変更することはできません。
def calculate():
result = 42 # この関数のローカル
return result
calculate()
print(result) # NameError、result はここに存在しないcount = 0
def increment():
global count # グローバルを変更したいと宣言する
count += 1
increment()
print(count) # 1global の使用は最後の手段にすべきです。コードの推論が難しくなります。値を渡して戻り値で返すことを優先してください。
*args と **kwargs
関数がいくつの引数を受け取るかわからないことがあります。*args は任意の数の位置引数をタプルに集めます。**kwargs は任意の数のキーワード引数を辞書に集めます。args と kwargs という名前は慣習であり、重要なのはアスタリスクです。
def total(*args):
return sum(args)
total(1, 2, 3) # 6
total(1, 2, 3, 4, 5) # 15def display(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
display(name="さくら", score=87, level=5)通常のパラメータと組み合わせることができます。通常のパラメータが最初に来ます:
def describe(title, *tags, **metadata):
print(f"{title} | tags: {tags} | meta: {metadata}")
describe("Python intro", "beginner", "python", author="さくら", year=2024)ドキュメンテーション文字列(docstring)
docstring は関数の先頭にある文字列で、その関数が何をするかを記述します。Python のエディタやツールはこれを使って、関数呼び出しにホバーしたときにヘルプを表示します。三重引用符を使い、シンプルな関数には1行で書きます。
def normalise(value, min_val, max_val):
"""既知の最小値と最大値が与えられたときに、値を 0-1 の範囲にスケールする。"""
return (value - min_val) / (max_val - min_val)def build_url(base, version, resource, *, secure=True):
"""
API エンドポイント URL を構築する。
完全修飾の URL 文字列を返す。secure が False の場合、
URL は https の代わりに http を使用する。
"""
scheme = "https" if secure else "http"
base = base.replace("https://", "").replace("http://", "")
return f"{scheme}://{base}/{version}/{resource}"名前とシグネチャから明らかに自己説明的でない関数には、docstring を書きましょう。
型ヒント
型ヒントを使うと、関数が期待する型と返す型を注釈できます。Python は実行時にこれを強制しませんが、エディタはこれを使って実行する前に間違いを検出します。コロンの前の -> は戻り値の型を指定します。
def greet(name: str, score: int) -> str:
return f"{name} scored {score}"def log(message: str) -> None:
print(f"[LOG] {message}")def top_scores(scores: list[int], n: int) -> list[int]:
return sorted(scores, reverse=True)[:n]型ヒントはオプションですが、複数の場所から呼び出される関数では有用です。これらはツールが検証できるドキュメントです。
値としての関数
Python の関数は文字列や数値と同じように値です。変数に代入したり、他の関数に渡したりできます。これが sorted() が key= 関数を受け取る仕組みです。
def double(x):
return x * 2
def apply(func, value):
return func(value)
apply(double, 5) # 10引数として関数を渡すことは、sorted()、map()、filter() で常に出てきます。Lambda、内包表記、zip の章でも見ることになります。
実践
連携する2つの関数: letter_grade はスコアを文字に変換し、summarise はリスト内のすべてのスコアに対してそれを呼び出します:
def letter_grade(score: int) -> str:
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
def summarise(scores: list[int]) -> None:
total = sum(scores)
avg = total / len(scores)
grades = [letter_grade(s) for s in scores]
print(f"Average: {avg:.1f}")
print(f"Grades: {', '.join(grades)}")
summarise([87, 92, 74, 65, 91])
