Courses

関数はPythonプログラミング言語における不可欠な要素です。Python本体や豊富なライブラリ群には優れた組み込み関数が多数あり、既にいくつか使ったことがあるかもしれません。とはいえ、データサイエンティストであれば、手元のデータが突きつける課題を解くために、自分で関数を書く場面が絶えずあります。
本チュートリアルはPython 3の構文を用います。すべての例はPython 3.10以降で動作し、最新の慣例(f文字列、型ヒント、位置専用・キーワード専用パラメータ)を反映しています。現在の安定版はPython 3.14です。
ここで紹介するコードを手元で簡単に実行するには、Pythonがあらかじめインストールされ、全サンプルコードを含む無料の DataLab ワークブックを作成してください。Python関数の練習には、このハンズオン演習や、Python Data Science Toolboxコースもおすすめです!
Pythonの関数
プログラミングで関数を使うのは、繰り返し使いたい一連の指示をまとめたり、複雑さゆえにサブプログラムとして独立させて必要なときだけ呼び出したほうがよい処理を切り出したりするためです。つまり関数は、特定のタスクを実行するために書かれたコード片です。特定のタスクを実行するために、入力が複数必要な場合もあれば、不要な場合もあります。タスクを終えた後、値を返す場合もあれば、返さない場合もあります。
Pythonの関数には次の3種類があります。
-
組み込み関数。たとえばヘルプを表示する
help()、最小値を得るmin()、オブジェクトを端末に表示するprint()など。ほかの関数の一覧はこちらにあります。 -
ユーザー定義関数(UDF)。ユーザーが自分のために作る関数。
-
無名関数。標準の
defキーワードで宣言しないため、ラムダ関数とも呼ばれます。
関数とメソッドの違い
メソッドとは、クラスの一部である関数を指します。クラスのインスタンス(オブジェクト)を通じてアクセスします。関数はこの制約がなく、独立した関数を指します。つまり、すべてのメソッドは関数ですが、すべての関数がメソッドとは限りません。
次の例では、まず関数plus()を定義し、続いてsum()メソッドを持つSummationクラスを定義しています。
Summationクラスの一部であるsum()メソッドを呼び出すには、まずそのクラスのインスタンス(オブジェクト)を作成する必要があります。では、そのオブジェクトを定義しましょう。
一方、関数plus()を呼び出すのにインスタンス化は不要であることに注意してください。DataCamp Lightのコードチャンクでplus(1,2)を問題なく実行できます。
パラメータと引数の違い
パラメータは、関数やメソッドを定義するときに使う名前で、呼び出し時に渡された引数がここに対応づけられます。言い換えると、引数は関数やメソッド呼び出しの際に渡される実際の値であり、関数やメソッドのコードはそれらをパラメータ名で参照します。
次の例を考え、先ほどのDataCamp Lightのチャンクを振り返ってください。Summationクラスのsum()メソッドには引数を2つ渡していますが、事前に定義したパラメータはself、a、bの3つでした。
selfはどうなったのでしょうか?
すべてのクラスメソッドの最初の引数は、常にそのクラスの現在のインスタンスへの参照です。この例ではSummationです。慣例として、この引数はselfと呼ばれます。
つまり、この場合selfはメソッドが呼び出されるインスタンスを参照する暗黙の引数であり、引数リストに自動的に挿入されるため、明示的に渡す必要はありません。
関数の定義方法:ユーザー定義関数(UDF)
Pythonで関数を定義する手順は次の4つです。
-
defキーワードで関数を宣言し、その後に関数名を続けます。 -
関数にパラメータを追加します。パラメータは関数の丸括弧内に記述します。行末はコロンで終えます。
-
関数が実行すべき文を記述します。
-
関数が何かを出力する必要がある場合は、最後にreturn文を書きます。return文がない場合、関数は
Noneを返します。
もちろん、関数は進むにつれて複雑になります。for文やフロー制御などを追加して、より細やかな処理にできます。
def hello():
name = input("Enter your name: ")
if name:
print(f"Hello {name}")
else:
print("Hello World")
hello()
上の関数では、ユーザーに名前の入力を求めます。名前が入力されなければ「Hello World」を表示し、入力があればパーソナライズした「Hello」を返します。
ヒント:UDFには1つ以上のパラメータを定義できます。これは関数の引数のセクションで詳しく扱います。さらに、関数の結果として1つまたは複数の値を返すことも、返さないこともできます。
return文
UDFのhello()で何かをprintしているだけであれば、必ずしもreturnする必要はありません。上の関数と次の関数の間に違いはありません。
しかし、関数の結果をさらに使って何らかの処理を行いたい場合は、実際に値(文字列、整数など)を返すためにreturn文が必要です。次の状況を考えてみましょう。hello()は文字列"hello"を返し、hello_noreturn()はNoneを返します。
2つ目の関数ではエラーになります。Noneに対しては演算を実行できないためです。TypeErrorが発生し、NoneType(hello_noreturn()の結果であるNone)とint(2)の乗算はできないと示されます。
Tip 関数はreturn文に到達すると即座に終了します。たとえ値を返さない場合でも同様です。
return文で覚えておきたいもう1点は、複数の値を返せることです。そのためにタプルを使います。
Remember タプルはリストに似たデータ構造で、複数の値を格納できます。ただしタプルはイミュータブルで、中身を変更できません。丸括弧()で構築します。カンマと代入演算子を使って、タプルを複数の変数にアンパックできます。
関数が複数の値を返す方法は、次の例で確認してください。
Note return sum, aというreturn文はreturn (sum, a)と同じ結果になります。前者は実際にはsumとaを裏側でタプルにパックしています。
関数の呼び出し方
これまでのセクションで、関数の呼び出し方法はすでに多く見てきました。関数を呼び出すとは、定義した関数を実行することです。Pythonのプロンプトから直接実行しても、別の関数から呼び出しても構いません(「入れ子の関数」で後述)。
新しく定義したhello()は、次のDataCamp Lightのチャンクのようにhello()と実行するだけで呼び出せます。
Python関数にドックストリングを追加する方法
Pythonで関数を書くうえで欠かせないのがドックストリングです。ドックストリングは、関数が何をするか(実行する計算や返り値など)を記述します。関数定義全体を追わなくても、ドックストリングを読めば関数の役割が理解できるようにするためのドキュメントです。
関数のドックストリングは、関数ヘッダーの直後の行に、三重引用符で挟んで記述します。hello()関数にふさわしいドックストリングは『“Hello World”を表示する』のようなものです。
def hello() -> None:
"""Prints "Hello World"."""
print("Hello World")
Note ドックストリングはここでの例より長くても構いません。詳細を学ぶには、scikit-learnやpandasなどのPythonライブラリのGithubリポジトリを参照すると、多数の好例が見つかります。
型ヒント
ドックストリングに密接に関連し、現代的なPythonコードでほぼ同じくらい一般的なのが型ヒントです。Python 3.5以降では、関数のパラメータや返り値に想定される型を注釈として付けられます。最も簡単な例を示します。
def plus(a: int, b: int) -> int:
return a + b
各パラメータの後ろの: intは「整数であるべき」を意味し、丸括弧の後ろの-> intは「この関数は整数を返す」を意味します。Python自体は実行時にこれらの注釈を強制しません。つまりplus()に文字列を渡しても、何かが壊れるまではPythonは文句を言いません。しかし、mypyやpyright、VS CodeやPyCharmなどのエディタに組み込まれた型チェッカーは、これらのヒントを用いてコードを実行する前にバグを検出します。
より複雑な型については、組み込みのジェネリクス(Python 3.9以降)を直接使うか、typingモジュールからインポートできます。
def greet(names: list[str]) -> None:
for name in names:
print(f"Hello {name}")
def find_user(user_id: int) -> dict | None:
# returns the user dict, or None if not found
...
Pythonの関数引数
先ほど、パラメータと引数の違いを学びました。要するに、引数は関数やメソッド呼び出し時に渡す実際の値であり、関数やメソッドのコードはそれらをパラメータ名で参照します。PythonのUDFが受け取れる引数には次の4種類があります。
- デフォルト引数
- 必須引数
- キーワード引数
- 可変個引数
デフォルト引数
デフォルト引数は、関数呼び出し時に値が渡されなかった場合に既定値を取る引数です。次の例のように、代入演算子=で既定値を指定できます。
必須引数
名前の通り、UDFに必ず含めるべき引数です。関数呼び出し時に、かつ正しい順序で渡す必要があります。次の例のとおりです。
aとbのパラメータに対応する引数が必要です。aとbの順序を入れ替えても結果は同じですが、plus()を次のように変更すると違いが出るかもしれません。
キーワード引数
パラメータを正しい順序で呼び出していることを確実にしたいなら、キーワード引数を使えます。引数をパラメータ名で指定します。上の例を用いて、もう少し明確にしましょう。
キーワード引数を使えば、パラメータの順序を入れ替えても、実行結果は同じになることにも注意してください。
可変個引数
関数に渡す引数の数が正確にはわからない場合、*argsを用いた次の構文が使えます。
アスタリスク(*)は、すべての非キーワードの可変引数の値を保持する変数名の前に置きます。ここでは*varintや*var_int_argsなど、plus()関数に別の名前を渡しても構いません。
Tip:*argsをアスタリスク付きの別名に置き換えてみてください。上のコードが引き続き動作するのがわかります。
上の関数は、渡されたすべての引数の合計を求めるために、Pythonの組み込み関数sum()を使っています。
グローバル変数とローカル変数
一般に、関数本体の内側で定義された変数はローカルスコープを持ち、外側で定義された変数はグローバルスコープを持ちます。つまり、ローカル変数はその関数ブロック内で定義され、その関数内からのみアクセスできます。一方、グローバル変数はスクリプト内のすべての関数からアクセスできます。
関数本体内で定義したローカル変数totalをprintしようとすると、name 'total' is not definedというNameErrorが発生するのがわかります。一方、init変数は問題なく出力できます。
位置専用・キーワード専用パラメータ
Python 3.8以降では、関数シグネチャ内で2つの特別なマーカー「/」と「*」を使うことで、引数の渡し方をより厳密に制御できます。/の前にあるものは位置引数のみ、*の後にあるものはキーワード引数のみで渡せます。
def greet(name, /, greeting="Hello", *, punctuation="!"):
print(f"{greeting} {name}{punctuation}")
呼び出し側では次のように動作します。
greet("Alice") # works
greet("Alice", greeting="Hi") # works
greet("Alice", "Hi", punctuation="?") # works
greet(name="Alice") # TypeError: name is positional-only
greet("Alice", "Hi", "?") # TypeError: punctuation is keyword-only
なぜこうしたいのでしょうか。主な理由は2つあります。
第一に、位置専用パラメータを使えば、後からパラメータ名を変更しても、誰もその名前でキーワード指定できないため、既存コードを壊しません。
第二に、キーワード専用パラメータは、呼び出し側に何を渡しているかを明示させるため、オプションのフラグや設定が複数ある場合に可読性が上がります。
要するに、意図を明確に表現するきれいな方法です。
Pythonの無名関数
無名関数はPythonではラムダ関数とも呼ばれます。標準のdefキーワードではなく、lambdaキーワードで宣言するためです。
上のDataCamp Lightチャンクでは、lambda x: x*2が無名(ラムダ)関数です。xが引数で、x*2が評価されて返される式または命令です。この関数の特別な点は、チュートリアル前半の例と異なり、名前を持たないことです。これをUDFで書くと、次のようになります。
def double(x):
return x*2
2つの引数を扱うラムダ関数の例も見てみましょう。
無名関数は、短時間だけ必要で、実行時に作成される名前のない関数が欲しいときに使います。具体的には、filter()、map()、reduce()を使う場面で有用です。
filter()関数は名前の通り、元の入力リストmy_listを条件>10に基づいてフィルタします。一方map()では、リストmy_listのすべての要素に関数を適用します。この例では、すべての要素を2倍しています。
reduce()関数はfunctoolsライブラリの一部です。my_listの要素に対して左から右へと累積的に処理を行い、この例ではシーケンスを単一の値55に還元します。
Pythonでmain()を関数として使う
Javaなど他の言語の経験があれば、関数を実行するのにmain関数が必要だとご存じでしょう。上の例で見たように、Pythonでは必ずしも必要ではありません。ただし、main()関数を設けるとコードを論理的に構造化しやすく、重要な要素をmain()にまとめられます。
main()関数は、これまでの関数と同様に簡単に定義して呼び出せます。
しかし、このままではモジュールとしてインポートしたときにもmain()のコードが実行されてしまいます。これを避けるには、__name__ == '__main__'のときにmain()を呼び出します。
つまり、上のコードチャンクは次のようになります。
Note __main__関数のほかに、クラスやオブジェクトのインスタンスを初期化する__init__関数もあります。簡単に言えばコンストラクタ(初期化子)として機能し、クラスの新しいインスタンスを作成すると自動的に呼び出されます。この関数では、新しく作られたオブジェクトが、本チュートリアルで先ほど見たselfパラメータに割り当てられます。次の例を見てください。
class Dog:
"""A simple Dog class.
Args:
legs: Number of legs so that the dog can walk.
color: The color of the fur.
"""
def __init__(self, legs: int, color: str) -> None:
self.legs = legs
self.color = color
def bark(self) -> str:
return "bark" * 2
if __name__ == "__main__":
dog = Dog(4, "brown")
print(dog.bark())
Pythonの関数に関するよくある質問
Pythonの関数とは何ですか?
関数は、特定のタスクを実行する再利用可能なコードのブロックです。入力を受け取り、処理し、出力を返すことができます。
Pythonで関数をどのように定義しますか?
Pythonで関数を定義するには、defキーワードを使い、関数名を付け、必要に応じて丸括弧にパラメータを指定し、処理内容を書き、必要ならreturnで値を返します。
Pythonにおける関数とメソッドの違いは何ですか?
関数は独立して存在しますが、メソッドはクラスに属します。すべてのメソッドは関数ですが、すべての関数がメソッドとは限りません。
Pythonの関数の種類は何ですか?
Pythonには、組み込み関数(print()など)、ユーザー定義関数(自作)、無名関数(短命なlambda関数)があります。
パラメータと引数の違いは何ですか?
パラメータは関数定義内の受け皿で、引数は関数を呼び出す際に実際に渡す値です。
ラムダ関数とは何ですか?
ラムダ関数は、手早い処理のための1行で書ける名前のない関数です。
__main__ 関数を使う理由は?
__main__はコードを整理し、スクリプトを直接実行したときだけ特定の部分が動き、インポート時には動かないようにする仕組みです。
グローバル変数とローカル変数の違いは何ですか?
グローバル変数はどこからでも使えますが、ローカル変数はその関数の内部でのみ有効です。