TL;DR
関数は処理をまとめた再利用可能なコードである。関数は他のコードから切り離され、名前を付けられたコードである。
関数のポイント
- Python では関数もオブジェクト
- 関数を定義するには def と入力する
- 関数名の先頭は英字か
_
を使う
>>> def h():
... print('hello')
...
>>> type(h)
<class 'function'>
Python の関数には、3 つの特徴がある。
- 名前を持つ
- 手続きの流れを含む
- 返り値(return で定義)
関数の基本形
def hoge():
print('hello')
# 関数呼び出し
hoge()
# hello
関数名には小文字とアンダースコアを使う。引数のない呼び出しはエラーになる。
実引数と仮引数
関数定義時に使う引数を仮引数と呼び、関数呼び出し時に渡す引数を実引数と呼ぶ。関数の外からは実引数、関数の中では仮引数。
実引数を渡して関数を呼び出すとき、それらの値は関数内の対応する仮引数にコピーされる。
実引数が不足したり多かったりするとエラーになる。変数に関数を代入することもできる。
def w():
print('word')
h = w() # 変数に関数を代入
h
# word
def h(name):
print('hello ' + name)
h('john')
# hello john
位置引数
先頭から順に対応する位置の仮引数にコピーされる。
def menu(a, b, c):
"""位置引数"""
return {'A': a, 'B': b, 'C': c}
menu('X', 'Y', 'Z')
# {'A': 'X', 'B': 'Y', 'C': 'Z'}
仮引数にデフォルト値
関数の呼び出しには、デフォルト値を持たせられる。引数名=デフォルト値 といったように指定する。
def h(w='word'):
print(w)
h()
# word
引数を渡すと、その値が利用される。
def h(w='word'):
print(w)
h('change')
# change
キーワード引数
キーワード引数は関数の呼び出しで、仮引数名を指定して渡す実引数である。キーワード引数(実引数にセット) 呼び出し時の順番は呼び出し結果に影響しない。
def h(a, b):
return a
h(b=1, a=2) # キーワード引数
# 2
return 文
return 文を使うと、関数の戻り値を指定できる。return 文が実行されると、そこで処理が終了する。
def i(plus):
return plus + 1
i(2)
# 3
def h(n = 'guest'):
if n == 'guest':
return '名前を教えてください'
h()
# '名前を教えてください'
複数の引数をセットできる。以下、BMI を計算させてみる。
def bmi(h,w):
return w / (h/100) ** 2
bmi(174, 62)
# 20.478266613819528
return がない場合
return 文がない場合は None が返される。return 文が実行されない関数は保守性が低くなるので、常に return 文が実行されるように戻り値を書くべきである。
def no_r():
pass
print(no_r())
# None
可変長引数
可変長引数は、数が決まっていない引数を渡す方法である。関数の引数が任意の個数となっている。 可変長の引数を受け取る関数は、仮引数名に *
アスタリスクをつけて定義する。 仮引数に割り当てられなかった位置引数をタプルで受け取る。
# 慣例として *args と記述することが多い。
def h(*args):
for i in args:
print(i)
h('one', 'two', 'three')
# one
# two
# three
可変長のキーワード引数
アスタリスクを 2 つ使うことで、キーワード引数を 1 つの辞書にまとめることができる。可変長のキーワード引数を受け取る関数は、仮引数名にアスタリスクを 2 つ付けると定義できる。
# 慣例として **kwargs と記述することが多い。
def h(**kwargs):
print(kwargs)
h(a=10, b=20, c=30)
# {'a': 10, 'b': 20, 'c': 30}
キーワード専用引数
引数に単独の *
を付けた場合、*
以降の引数は、キーワード引数という形でしか渡せない。
def h(a, *, b):
print(f'{a} {b}')
h(1, b=2)
# 1 2
引数リストのアンパック
*
演算子は、リストや辞書に格納された値を引数に渡す機能である。
def print_page(one, two, three):
print(one)
print(two)
print(three)
contents = ['a', 'b', 'c']
print_page(*contents)
# a b c
**
演算子を使うと、辞書に格納している値をキーワード引数として渡す。
def print_page(one, two, three):
print(one)
print('2番目 - ', two)
print('3番目 - ', three)
dic = {'two' : 2, 'three' : 3}
print_page('1番目', **dic)
# 1番目
# 2番目 - 2
# 3番目 - 3
関数内関数
関数の中に関数を入れることも可能である。外側の関数から内側の関数を呼び出す。
関数内関数はクロージャ(ほかの関数によって動的に生成される関数)として機能し、自分の外で作られた変数の値を変更できる。
def out(a, b):
print('関数を呼び出します')
def inner(c, d):
return c + d
return inner(a, b)
out(2, 3)
# 関数を呼び出します
# 5
ラムダ関数
ラムダ関数は、一行で表現される無名関数である。無名関数とは、関数が必要なときにその場で定義する使い捨て関数である。無名が故に「関数名を考える必要がない」というメリットもある。
どんなときに使われるのかというと、関数を「引数」として受け取る関数を呼び出すときなど。
ラムダは 0 個以上のカンマ区切りの実引数を取り、後ろにコロンをつけ、関数定義をする。lambda では丸括弧を使わない。
無名関数は、関数の引数として関数オブジェクトを渡すときに利用される。式はそのまま返されるので、return 文は不要である。
lambda 引数1, 引数2 : 戻り値
b = lambda a : a + 1
b(2)
# 3
b = lambda a, b : a + b
b(1,2)
# 3
関数を引数として呼び出す。
n = ['Python', 'Rust', 'Go']
f = filter(lambda i: len(i) == 4, n)
list(f)
# ['Rust']
ジェネレーター関数
return を yield に変えれば、複数の値を一つずつ作り出すジェネレーターになる。ジェネレーター関数を使うことにより、yeild のところまで処理を進め一旦停止する。そして任意のタイミングで処理を再開することができる。
参考 : yield を使う関数をジェネレーター関数、内包表記を使うものをジェネレーター式という
次のコードは、next 関数が呼ばれるたびに、関数の中の処理が次の yield まで進んでいることを示している。値がなくなると例外 StopIteration が返る。
def g(n):
while n:
yield n
n -= 2
a = g(100)
next(a) # 100
next(a) # 98
next(a) # 96
デコレータ
ソースコードを書き換えずに、既存の関数に変更を加えたいことがある。デコレータは、既存関数に対してコードの変更なしに処理を追加する関数である。
def a(x):
def new_a():
print('before')
x()
print('after')
return new_a
@a
def b():
print('middle')
b()
# before
# middle
# after
型ヒント
関数には、アノテーション(タグ付け)を用いて型ヒント(関数の引数と戻り値に型情報を付ける機能)を追加できる。しかし、実行時に型チェックが行われるわけではない。あくまでも注釈であり、コードの保守性を向上させるために付与するのである。
使い方
- :の横に型を指定
- -> の横は返り値の型を指定
def w(a:int) -> int:
return a
w(3)
# 3
def greeting(name: str) -> str:
return 'Hello ' + name
再帰
関数が自分自身を呼び出すことを再帰という。再帰はリストのネストなど、平坦ではないデータを処理するときに役立つ。
def flat(x):
for i in x:
if isinstance(i, list):
for i_in in flat(i):
yield i_in
else:
yield i
x = [1, 2, [3, 4, 5], [6, [7, 8, 9]]]
list(flat(x))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Docstring
関数には Docstring を記述することができる。Docstring は、コメントと同じように何を書いてもよいが、エディタでヒントを出したときに理解の手助けとなるように、引数・戻り値・関数の概要を記述するとよい。
def print_page(one, two, three):
"""関数の概要
引数:
引数の説明
戻り値:
戻り値の説明
"""
print(one)
print(two)
print(three)
Google の Python Docstrings の例が記述してあるExample Google Style Python Docstrings — napoleon 0.7 documentationが、参考になる。
Docstring は複数行にまたがることがあり、段落が作られる。段落の題名:の後にインデントされたテキストのブロックが続く。
def function_with_types_in_docstring(param1, param2):
"""Example function with types documented in the docstring.
`PEP 484`_ type annotations are supported. If attribute, parameter, and
return types are annotated according to `PEP 484`_, they do not need to be
included in the docstring:
Args:
param1 (int): The first parameter.
param2 (str): The second parameter.
Returns:
bool: The return value. True for success, False otherwise.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""