関数はコードの塊に名前を付けたものです。関数を呼び出すことにより、いつでもまた何度でもそのコードの塊を実行することができます。
プログラムの中で同じコードの塊がいくつもある場合、そのコードの塊を関数の中にまとめるとい良いでしょう。一度コードを関数にまとめれば、関数を呼び出すだけで何度でも同じコードを実行できます。コードを保守するときも、プログラムのあちこちに散らばった同じコードをすべて確認する必要がなくなり、関数のみを確認するだけですみます。
また、一度だけしか呼び出されない関数というのもよくあります。論理的な機能(処理)を関数にまとめ、いくつもの小さな部品に分割することにより、プログラムが理解しやすく保守しやすいコードになるからです。
この記事では関数に関する内容について詳しく解説していきます。
関数を定義する
Pythonを含む多くのプログラミング言語では、事前に用意された関数(組み込み関数)を利用する以外に、独自に関数を定義して、それを使用することができます。
新しく関数を定義するには次の構文を使います。キーワードdefに続けて関数名を書き、その後に丸括弧を続けます。丸括弧の中にはオプションの引数リストを指定します。引数リストは複数の場合はカンマ(,)で区切って指定します。そして最後にコロン(:)を書きます。関数本体はPythonの1つ以上の文です。これはインデントされていなければなりません。
def 関数名(引数1, 引数2, ...):
関数本体
関数名は変数名と同じルールに従います。したがって関数名に日本語などの非ASCII文字も使えますが、実用上は以下の規則に従うのが良いでしょう。
- 使用できる文字は小文字と大文字のアルファベット(a-zとA-Z)、数字(0-9)、アンダースコア(_)
- 先頭の文字はアフファベットかアンダースコア(ただし先頭がアンダースコアの名前は特別な意味を持つ)
- Pythonの予約後は使えない
- 大文字と小文字は区別される
またPythonでは関数名はすべて小文字、かつスネークケース(単語をアンダースコアで区切る記述方法)で記述するのが慣習です(例:my_first_function)。
いくつか関数定義の例を見てみましょう。最初は引数を取らないsay_hello_world()関数を定義します。この関数の本体には1つの文があります。
>>> def say_hello_world():
... print('Hello, World!')
...
次のprint_word()関数は引数を1つ取り、その引数を表示します。関数本体の中で仮引数は変数のように扱うことができます。
>>> def print_word(word):
... print(word)
...
関数が複数の引数を取る場合は、カンマ(,)で区切って指定します。print_words()関数は2つの引数をつなげて表示します。
>>> def print_words(word1, word2):
... print(word1 + word2)
...
ドキュメンテーション文字列(docstring)
関数定義にはドキュメントを付けることができます。関数本体の最初の行に文字列リテラルを記述すると、この文字列は関数のドキュメンテーション文字列(docstringともいう)になります。関数にドキュメンテーション文字列を入れるのは良い習慣です。
>>> def print_word(word):
... """与えられた単語を標準出力へ表示する。"""
... print(word)
...
このドキュメンテーション文字列はツールでドキュメントを自動生成したり、ユーザーが参照するために使われます。対話的インタープリタから使用できるツールの一つに組み込みのhelp()関数があります。help()関数の引数として関数名を渡すと、引数リストと共にフォーマットされたドキュメンテーション文字列が返されます。
>>> help(print_word)
Help on function print_word in module __main__:
print_word(word)
与えられた単語を標準出力へ表示する。
(END)
フォーマットされる前のドキュメンテーション文字列は関数オブジェクトの__doc__属性で参照できます。関数オブジェクトについては後述します。
>>> print(print_word.__doc__)
与えられた単語を標準出力へ表示する。
ドキュメンテーション文字列の書き方にはいくつかの慣習があります。Pythonのドキュメントにも慣習についての記載があるので、その部分を次に引用します。
最初の行は、常に対象物の目的を短く簡潔にまとめたものでなくてはなりません。簡潔に書くために、対象物の名前や型を明示する必要はありません。名前や型は他の方法でも得られるからです (名前がたまたま関数の演算内容を記述する動詞である場合は例外です)。最初の行は大文字で始まり、ピリオドで終わっていなければなりません。
ドキュメンテーション文字列中にさらに記述すべき行がある場合、二行目は空行にし、まとめの行と残りの記述部分を視覚的に分離します。つづく行は一つまたはそれ以上の段落で、対象物の呼び出し規約や副作用について記述します。
4.8.7 ドキュメンテーション文字列 | Pythonチュートリアル
ドキュメンテーション文字列の例の記述もあるのでそちらも引用しておきます。
4.8.7 ドキュメンテーション文字列 | Pythonチュートリアル>>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print(my_function.__doc__) Do nothing, but document it. No, really, it doesn't do anything.
ローカル変数
関数の中で定義される変数はローカル変数と呼ばれます。この変数は関数の内部からしかアクセスできないため(つまり関数にローカルな変数のため)このように呼ばれます。
ここで覚えておいてほしいことは、関数の外側にローカル変数と同じ名前の変数があっても、それらの変数とはまったくの別物だということです。そのため関数の外側でどのよう名前が使われていようが、関数内部でそれを気にする必要はありません。
ローカル変数の動作を少し確認してみましょう。
>>> outer = 'outer'
>>> var = 'outer var'
>>> def foo():
... var = 'inner var'
... print(var)
... print(outer)
...
>>> foo()
inner var
outer
>>> print(var)
outer var
関数の中のprint(var)は、ローカル変数varを参照します。print(outer)はouterという変数を探しますが、関数内部では見つからないので関数の外側を探し、そこで見つけたouter変数の内容を表示します。
トップレベルのprint(var)は、トップレベルの変数varの内容を表示します。関数内部でvar変数に値を代入していますが、ローカル変数のvarとトップレベルのvar変数は(名前は同じでも)別物なのでトップレベルのvar変数は何も変わりません。
このような動作の詳しいことは名前空間とスコープを学ぶ必要がありますが、関数を定義するときには、関数の外側でどのような名前が使われているか気にせず(関数の外側に影響を与えず)、関数内部で自由に名前が使えることを覚えておいてください。
関数の呼び出し
関数を呼び出すには、関数名の後に丸括弧を付けます。引数が必要であれば括弧の中にそれらをリストします。
先ほど定義した関数を呼び出してみよう。関数を呼び出すと制御は呼び出し元から関数に移り、関数本体が実行されます。関数の最後まで実行されると制御は呼び出し元に戻り、関数呼び出しの次の文から(もしあれば)実行を続けます。
>>> say_hello_world()
Hello, World!
関数に引数が必要であれば、括弧の中にそれらをリストします。実引数は仮引数にコピーされてから関数本体が実行されます。
>>> print_word('Foo')
Foo
複数の実引数はカンマで区切って指定します。
>>> print_words('Foo', 'Bar')
FooBar
関数の戻り値
関数は値を返すことができます。これは関数の戻り値(返り値とも言う)と呼ばれます。関数から値を返すにはreturn文を使います。
試しに値を返す関数を定義して、それを呼び出してみましょう。add()関数は2つの引数を取り、それらの引数を加算した値を戻します。
>>> def add(operand1, operand2):
... return operand1 + operand2
...
>>> add(2, 3)
5
(対話的インタープリタの機能で関数の戻り値が表示されますが、)ここで関数が返す値は単に捨てています。関数の戻り値を後で使いたい場合は、変数に保存します。
>>> result = add(2, 3)
>>> result
5
関数の呼び出しは変数が書けるところであればどこでも書くことができます。少し寄り道をしてこの式を少し詳しくみてみましょう。「add(2, 3)」の関数呼び出しが実行される(専門的な用語で評価するという)と「add(2, 3)」と言う部分は値5を持ちます。「add(2, 3)」の部分が「5」に置き換わると考えるとわかりやすいでしょう。そしてその値「5」がresult変数に代入されます。
このような動作を理解しておくと次のような式の意味も簡単に理解できるでしょう。add()関数の呼び出し部分は評価されると、それぞれの戻り値である5と7の値を持ちます。その後、それらが加算され値12を持ち、その結果がresult変数に代入されます。
>>> result = add(2, 3) + add(3, 4)
>>> result
12
return文は関数の実行を終了する
正確にいうとreturn文は関数の実行を終了させ、制御を呼び出し元に戻します。もしreturn文に値が指定されていれば、その値を呼び出し元に戻します。
関数の実行を終了し、呼び出し元に制御を戻すだけの目的であれば、return文に戻り値を指定する必要はありません。そのようなreturn文の例を見てみましょう。次の例は引数に渡されたリストの要素を順にチェックし、要素が数値5の場合に関数の実行を終了して制御を呼び出し元に戻します。
>>> def exit_by_five(nums):
... for i in nums:
... if i == 5:
... return
... else:
... print(i)
...
>>> exit_by_five([3, 1, 5, 7, 8])
3
1
このコードはfor文で順に要素を確認して、要素が5でなければそれを表示します。要素が5の時はif文の本体、つまりreturn文が実行されて関数の実行は終了します。そのため要素の7や8は表示されることはありません。
明示的に値を返さない関数はNoneを返す
return文がない関数も実は値を返します。その戻り値はNoneです。前述したhelloworld()関数で確認してみましょう。
>>> result = say_hello_world()
Hello, World!
>>> result is None
True
明示的に値を返さないreturn文もNoneを返します。
>>> def do_nothing():
... return
...
>>> do_nothing() is None
True
関数の引数
Pythonは関数の引数について知っておくべきことがいくつかあります。ここでは引数の基本的なことについて解説します。可変長引数や引数のアンパックについては別途解説します。
位置引数
位置引数は渡された引数の位置、つまり引数が渡された順番が重要な意味を持つ引数です。実引数は指定された順番に、対応する仮引数にコピーされます。
次のような関数を定義して位置引数について確認してみましょう。
>>> def sub(a, b):
... return a - b
...
次のように実引数を渡すと、実引数5は仮引数aにコピーされ、実引数3は仮引数bにコピーされてから関数本体が実行されます。
>>> sub(5, 3)
2
実引数の順序を入れ替えると結果も変わります。
>>> sub(3, 5)
-2
キーワード引数
キーワード引数は、関数を呼び出すときに仮引数に実引数を代入する形式で引数を渡します。この場合、関数定義とキーワード引数を指定する順序は異なっていても構いません。
>>> sub(b=3, a=5)
2
>>>
位置引数とキーワード引数の両方を使う場合、キーワード引数は位置引数の後でなければなりません。
>>> def func(foo, bar, baz):
... print(foo, bar, baz)
...
>>> func('Foo', baz='Baz', bar='Bar')
Foo Bar Baz
引数のデフォルト値
引数にはデフォルト値を指定することもできます。デフォルト値は対応する実引数が渡されなかったときに使われます。デフォルト値は関数定義で「引数=デフォルト値」の形式で指定します。
>>> def func(foo, bar='bar', baz='baz'):
... print(foo, bar, baz)
...
foo引数には実引数を渡す必要がありますが、それ以外に実引数を渡さなかった場合はデフォルト値が使用されます。
>>> func('one', 'two')
one two Baz
>>> func('one', baz='three')
one Bar three
位置専用引数とキーワード専用引数
可読性とパフォーマンスのために引数の渡し方を制限することもできます。そのような関数定義のヘッダー部分は次のようになります。
def f(位置専用, ..., /, 位置かキーワード, ..., *, キーワード専用, ...):
スラッシュ(/)とアスタリスク(*)はオプションです。スラッシュを指定した場合、スラッシュより前の引数は位置専用引数になります。つまり実引数は位置引数として渡す必要があります。スラッシュより後ろは位置引数かキーワード引数を使うことができます。ただし、アスタリスクより後ろの引数はキーワード専用引数となり、引数はキーワード引数で渡す必要があります。
>>> def f(pos1, pos2, /, pos_kwd1=1, pos_kwd2=2, *, kwd1=3, kwd2=4):
... print(pos1, pos2, pos_kwd1, pos_kwd2, kwd1, kwd2)
...
>>> f('a', 'b', 'c', pos_kwd2='d', kwd1='e', kwd2='f')
a b c d e f
>>> f('a', 'b', pos_kwd1='c', kwd2='f')
a b c 2 3 f
可変長引数
Pythonでは可変長引数の関数も定義できます。つまり関数で任意の個数の引数を受け付けるようにすることができます。
位置引数をタプルにまとめる
関数定義の仮引数の名前の前にアスタリスク(*)を付けると、それに対応する位置引数はタプルにまとめられます。関数の中で、まとめられたタプルを参照するのにアスタリスクは必要ありません。
>>> def print_args(*args):
... print(args)
...
この関数を呼び出してみます。
>>> print_args()
()
>>> print_args(1, 'b', 3)
(1, 'b', 3)
*args引数の前に通常の仮引数を置くこともできます。その場合は残りすべての実引数がタプルにまとめられます。
>>> def print_args2(foo, bar, *args):
... print(foo, bar)
... print(args)
...
>>> print_args2(1, 2, 'a', 'b')
1 2
('a', 'b')
*args引数の後ろにも仮引数を置くことはできますが、この仮引数にはキーワード引数でしか値を渡すことはできません。
>>> def print_args3(foo, bar, *args, baz):
... print(foo, bar)
... print(args)
... print(baz)
...
>>> print_args3(1, 2, 'a', 'b', 'c')
1 2
('a', 'b', 'c')
0
>>> print_args3(1, 2, 'a', 'b', baz='c')
1 2
('a', 'b')
c
キーワード引数を辞書にまとめる
仮引数の名前の前に2つのアスタリスク(**)を付けると、キーワード引数を1つの辞書にまとめることができます。引数の名前は辞書のキーに、値は辞書の値になります。
>>> def print_kwargs(**kwargs):
... print(kwargs)
...
**kwargs引数に対応する引数がない場合は空の辞書になります。対応するキーワード引数は辞書にまとめられます。
>>> print_kwargs()
{}
>>> print_kwargs(hoo=1, bar='a')
{'hoo': 1, 'bar': 'a'}
関数定義で*argsと**kwargsの両方を使う場合、*argsは**kwargsの前に置く必要があります。
>>> def print_args4(pos, *args, **kwargs):
... print(pos)
... print(args)
... print(kwargs)
...
この関数を呼び出してみましょう。
>>> print_args4(1, 2, 3, four=4, five=5)
1
(2, 3)
{'four': 4, 'five': 5}
引数のアンパック
アスタリスク(*)には別の使い方もあります。実引数がリストやタプルの場合、関数を呼び出す際に*を使ってそれらをアンパックすることができます。
例えば組み込みのprint関数は可変個の引数を受け付けます。このprint関数にリストの要素をそれぞれ次のように渡すことができます。
>>> args = [1, 2, 3]
>>> print(args[0], args[1], args[2])
1 2 3
しかし、このような場合はリストやタプルに*演算子を付けて渡すとアンパックされて引数が渡されます。
>>> print(*args)
1 2 3
同様に辞書に**演算子を付けて、辞書をアンパックしてキーワード引数として渡すことができます。
>>> def size(height, width, depth):
... print(height, width, depth)
...
>>> kwargs = {"width": 100, "height": 50, "depth": 30}
>>> size(**kwargs)
50 100 30
**kwargsを引数として渡すことは、次のようにキーワード引数を渡すのと同様の効果を持ちます。
>>> size(width=100, height=50, depth=30)
50 100 30
関数オブジェクト
Pythonでは、すべてのものがオブジェクトです。数値、文字列、リストなどはもちろん関数もやはりオブジェクトです。したがって、関数もオブジェクトとして変数に代入したり、他の関数の引数として渡すことができます。
>>> def echo(msg):
... print(msg)
...
>>> echo('foo')
foo
echo()関数を変数に代入してみましょう。関数をオブジェクトとして扱う場合は関数名だけを指定します。関数オブジェクトを代入した変数に()をつければ、代入した関数を呼び出すこともできます。
>>> alias = echo
>>> alias('bar')
bar
同様に関数オブジェクトを他の関数の引数として渡すことができる。
>>> def run_function(func, msg):
... func(msg)
...
>>> run_function(echo, 'baz')
baz
まとめ
関数を使い始めるのに必要な内容はこの記事ですべて説明しました。もっと高度な内容もありますが、それはまた別の機会に解説したいと思います。