[解決!Python]関数の定義の仕方まとめ:解決!Python
Pythonで関数を定義する基本、位置引数やキーワード引数の渡し方と受け取り方、デフォルト引数値の指定、可変長引数の渡し方と受け取り方などを紹介する。
関数定義の基本型
# パラメーターがなく、戻り値もない関数
def helloworld():
print('hello world')
helloworld() # hello world
# パラメーターがなく、戻り値がある関数
from datetime import datetime
def get_now():
return datetime.now().strftime('%Y/%m/%d %H:%M:%S')
result = get_now()
print(result) # 2022/05/04 15:21:42など
# パラメーターがあり、戻り値はない関数
def hello(whom):
print(f'Hello, {whom}')
hello('world') # Hello, world
# パラメーターと戻り値がある関数
def plus(x, y):
return x + y
result = plus(1, 2)
print(result) # 3
# 複数の値を返す関数
def multi_vals(x, y):
return x + y, x - y
result = multi_vals(1, 2)
print(result) # (3, -1)
total, diff = multi_vals(1, 2)
print(f'total: {total}, difference: {diff}') # total: 3, difference: -1
# 位置引数とキーワード引数
def pos_and_kwd(x, y):
print(f'x: {x}, y: {y}')
pos_and_kwd(1, 2) # 位置引数:x: 1, y: 2
pos_and_kwd(y=2, x=1) # キーワード引数:x: 1, y: 2
# デフォルト引数値の指定
def default_arg_value(x=1, y=2):
print(f'x: {x}, y: {y}')
default_arg_value() # x: 1, y: 2
詳細は以下の「関数定義の基本型」を参照のこと。
位置専用パラメーターとキーワード専用パラメーター
# 位置専用パラメーターの指定
def positional_only(a, b, /, c, d): # aとbにはキーワード引数として値を渡せない
print(f'a: {a}, b: {b}, c: {c}, d: {d}')
positional_only(1, 2, c=3, d=4) # OK: a: 1, b: 2, c: 3, d: 4
positional_only(a=1, b=2, c=3, d=4) # TypeError
# キーワード専用パラメーターの指定
def keyword_only(a, b, *, c, d): # cとdにはキーワード引数としてしか値を渡せない
print(f'a: {a}, b: {b}, c: {c}, d: {d}')
keyword_only(1, 2, c=3, d=4) # OK: a: 1, b: 2, c: 3, d: 4
keyword_only(1, 2, 3, 4) # TypeError
# 位置専用とキーワード専用の混在
def pos_and_kw(a, b, /, c, d, *, e, f): # cとdはどちらでもよい
print(f'a: {a}, b: {b}, c: {c}, d: {d}, e: {e}, f: {f}')
pos_and_kw(1, 2, 3, 4, f=6, e=5) # OK: a: 1, b: 2, c: 3, d: 4, e: 5, f: 6
pos_and_kw(1, 2, f=6, e=5, d=4, c=3) # OK
詳細は以下の「位置専用パラメーターとキーワード専用パラメーター」を参照のこと。
可変長引数
# 可変長位置パラメーター
def varpos(a, b, *args): # argsにはa、bが受け取ったもの以外が渡される(タプル)
print(f'a: {a}, {b}, args: {args}')
varpos(1, 2, 3, 4, 5) # a: 1, 2, args: (3, 4, 5)
varpos(1, 2, (3, 4, 5)) # a: 1, 2, args: ((3, 4, 5),)
lst = [1, 2, 3, 4, 5]
varpos(*lst) # a: 1, 2, args: (3, 4, 5)
# 可変長キーワードパラメーター
def varkwd(*, a, b, **kwargs):
print(f'a: {a}, b: {b}, kwargs: {kwargs}')
varkwd(b=2, a=1, d=4, c=3) # a: 1, b: 2, kwargs: {'d': 4, 'c': 3}
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
varkwd(**d) # a: 1, b: 2, kwargs: {'c': 3, 'd': 4}
# 可変長位置パラメーターと可変長キーワードパラメーターの混在
def varargs(a, b, *args, **kwargs):
print(f'a: {a}, b: {b}, args: {args}, kwargs{kwargs}')
varargs(1, 2, 3, d=4, e=5) # a: 1, b: 2, args: (3,), kwargs{'d': 4, 'e': 5}
詳細は以下の「可変長引数」を参照のこと。
関数定義の基本型
関数はdef文を用いて定義する。
具体的にはキーワード「def」に続けて、関数名を記述し、その後にその関数の呼び出し時に渡される実引数を受け取るパラメーターをかっこ「()」で囲んで記述する。パラメーターが複数あるときにはカンマ「,」でそれらを区切る(並べられたパラメーターのことを「パラメーターリスト」と呼ぶこともある)。行末にはコロン「:」が必要なことに注意。
関数が実行する処理は、「def 関数名(パラメーターリスト):」行に続けて、インデントを付けて記述する(これを「関数本体」「関数ボディー」などと呼ぶことがある)。その関数が値を返す場合(これを「戻り値」「返り値」などと呼ぶ)、関数本体のどこかで「return 戻り値」を記述する。
def func_name(param1, param2, ……):
# 関数本体:関数が行う処理はインデントを付けて記述する
return_value = ……
return return_value # 関数が値を返す場合にはreturn文を記述する
以下はパラメーターも戻り値もないシンプルな関数の定義例だ。
def helloworld():
print('hello world')
helloworld() # hello world
return文を使って値を返さない関数(戻り値がない関数)でも、実際にはPythonのNone値が返されていることは覚えておこう。以下に例を示す。
result = helloworld()
print(result is None) # True:helloworld関数の戻り値はNone
パラメーターはないが、戻り値がある関数の例を以下に示す。
from datetime import datetime
def get_now():
return datetime.now().strftime('%Y/%m/%d %H:%M:%S')
result = get_now()
print(result) # 2022/05/04 15:21:42など
この例では、datetimeモジュールのdatetime.nowメソッドを呼び出して取得した現在の日時を「YYYY/MM/DD hh:mm:ss」形式に変換して返している。多くの関数はパラメーターに渡された値を基に何らかの処理を行い、その結果を返す(またはその結果を外部ファイルや標準出力に出力する)のだが、このようにパラメーターを持たずに、何らかの値を返す関数もある。
逆にパラメーターはあるが、戻り値がない関数も存在する。以下に例を示す。
def hello(whom):
print(f'Hello, {whom}')
hello('world') # Hello, world
この例では、hello関数はパラメーターwhomに受け取った値を使って、f文字列を組み立て、それをprint関数で画面に表示している。関数本体がprint関数呼び出しのみであり、print関数には戻り値がないことから、hello関数にも戻り値がないことになる。
パラメーターと戻り値の両方がある関数の例を以下に示す。
def plus(x, y):
return x + y
result = plus(1, 2)
print(result) # 3
この例では、パラメーターxとyに受け取った値を加算(文字列であれば結合)した結果が戻り値として返される。
Pythonの関数は複数の値を(タプルにまとめて)返すことも可能だ。これを行うには、return文で返したい値をカンマ「,」で区切って並べればよい。並べられた値はタプルを構成する要素となり、タプルが関数の戻り値となる。
以下に例を示す。
def multi_vals(x, y):
return x + y, x - y
result = multi_vals(1, 2)
print(result) # (3, -1)
total, diff = multi_vals(1, 2)
print(f'total: {total}, difference: {diff}') # total: 3, difference: -1
multi_vals関数のreturn文では、2つのパラメーターに受け取った値を加算した結果と減算した結果をカンマで並べているので、これら2つの値がタプルとして返される。そのため、最初の「result = multi_vals(1, 2)」という行では変数resultにタプルが代入される。そのため「print(result)」行では「(3, -1)」という2つの値を格納するタプルが表示される。タプルの値は、(タプルの要素数と代入文の左辺にある変数の数が等しければ)アンパック(分解)して代入できる。そのため、「total, diff = multi_vals(1, 2)」行では加算結果が変数totalに、減算結果が変数diffに個別に代入される。
位置引数とキーワード引数
関数呼び出し時に実引数の値をパラメーターに引き渡す方法として、「位置引数」と「キーワード引数」の2種類がある。位置引数を使用する場合、関数呼び出し時にかっこの中に引数を並べた順に、関数のパラメーターにそれらが渡される。
例えば、次のような関数があったとする。
def pos_and_kwd(x, y):
print(f'x: {x}, y: {y}')
位置引数を使ってpos_and_kwd関数を呼び出すには次のようにする。
pos_and_kwd(1, 2) # x: 1, y: 2
実引数(関数呼び出し時に指定する引数)は1、2の順に並べられているので、pos_and_kwd関数のパラメーターxとyにはその順に値が引き渡される。そのため、パラメーターxの値は1に、パラメーターyの値は2になる。
キーワード引数の代表的な渡し方としては、「パラメーター名=値」のようにして、どのパラメーターにどの値を渡すのかを指定する方法がある(この他に「{パラメーター名: 値}」のような辞書を用意して、それらを展開して渡す方法もある)。以下に例を示す。
pos_and_kwd(y=2, x=1) # x: 1, y: 2
この例では「y=2, x=1」のようにパラメーターxの値は1、パラメーターyの値は2と指定している。そのため、結果は「x: 1, y: 2」となる。
位置引数とキーワード引数を混在させて指定することも可能だ。以下に例を示す。
pos_and_kwd(1, y=2) # x: 1, y: 2
pos_and_kwd(y=2, 1) # SyntaxError
上の例の1つ目のpos_and_kwd関数呼び出しでは、「1」が位置引数、「y=2」がキーワード引数として関数に渡されている。このとき注意したいのは、2つ目の呼び出しのように、キーワード引数を先に指定することはできない点だ。位置引数は常にキーワード引数よりも前に指定する必要がある。関数定義中でのパラメーターの列挙時も同様な制約がある。
デフォルト引数値の指定
関数のパラメーターにそのデフォルト値を指定することも可能だ(これを「デフォルト引数値」などと呼ぶ)。デフォルト引数値を指定すると、関数呼び出し時にその引数の値の指定を省略でき、その場合、そのパラメーターの値はデフォルト引数値となる。多くの場合は決まった値を指定すればよいが、時にはそれとは異なる値を指定する必要が出てくるといった場合に、デフォルト引数値を用いることで、コードの記述をシンプルにできる。
デフォルト引数値を指定するにはパラメーターリスト中で「パラメーター名=デフォルト引数値」のようにする。
以下に例を示す。
def default_arg_value(x=1, y=2):
print(f'x: {x}, y: {y}')
default_arg_value() # x: 1, y: 2
この例では、パラメーターリスト中で「x=1, y=2」としているので、xの値を指定しなければその値は1に、yの値を指定しなければその値は2になる。関数定義の直下でしているように、引数なしでこの関数を呼び出すと、今述べた通りの値が2つのパラメーターに代入されているのが分かるはずだ。
デフォルト引数値を持つパラメーターは、持たないパラメーターよりもパラメーターリスト中で後ろに置かなければならないことには注意すること。例えば、以下の例ではデフォルト引数値を持つパラメーターが、持たないパラメーターよりも前にあるのでSyntaxErrorとなる。
def bad_param_list(a=1, b=2, c, d): # SyntaxError
pass
位置専用パラメーターとキーワード専用パラメーター
特定のパラメーターを位置引数のみを受け取るように、あるいはキーワード引数のみを受け取るようにしたいときがあるかもしれない。例えば、先頭にある2つのパラメーターは特定の順番での指定が必須で、それ以外はキーワード引数として必要なものだけを指定してもらいたい、といった場合がそうだ。パラメーターリスト中に「/」または「*」を含めることで、どのパラメーターが位置引数専用でどのパラメーターがキーワード引数専用かを指定できる。
パラメーターリスト中に「/」を含めると、それよりも前にあるパラメーターについては位置引数として値を渡すことが強制される。以下に例を示す。
def positional_only(a, b, /, c, d): # xとyにはキーワード引数として値を渡せない
print(f'a: {a}, b: {b}, c: {c}, d: {d}')
positional_only(1, 2, c=3, d=4) # OK: a: 1, b: 2, c: 3, d: 4
positional_only(a=1, b=2, c=3, d=4) # TypeError
この例ではパラメーターaとbの後に、「/」がある。そのため、aとbには位置引数しか渡せない。そのため、2つ目の呼び出しでは例外が発生する。一方、「/」の後にあるパラメーターcとdに値を渡すには、位置引数もキーワード引数も使用できる。
パラメーターリスト中に「*」を含めると、それよりも後ろにあるパラメーターについてはキーワード引数として渡すことが強制される。以下に例を示す。
def keyword_only(a, b, *, c, d): # cとdにはキーワード引数としてしか値を渡せない
print(f'a: {a}, b: {b}, c: {c}, d: {d}')
keyword_only(1, 2, c=3, d=4) # OK: a: 1, b: 2, c: 3, d: 4
keyword_only(1, 2, 3, 4) # TypeError
この例では、「*」の後ろにあるパラメーターcとdにはキーワード引数を使ってしか値を渡せない。そのため、2つ目の呼び出しでは例外が発生する。「*」の前にあるパラメーターaとbには、位置引数を使ってもキーワード引数を使っても値を渡せる。
これらをパラメーターリストに混在させることも可能だ。以下に例を示す。
def pos_and_kw(a, b, /, c, d, *, e, f): # cとdはどちらでもよい
print(f'a: {a}, b: {b}, c: {c}, d: {d}, e: {e}, f: {f}')
pos_and_kw(1, 2, 3, 4, f=6, e=5) # OK: a: 1, b: 2, c: 3, d: 4, e: 5, f: 6
pos_and_kw(1, 2, f=6, e=5, d=4, c=3) # OK
この場合、パラメーターaとbは位置引数専用のパラメーターになり、cとdは位置引数でもキーワード引数でも受け取ることが可能で、eとfはキーワード引数専用となる。
可変長引数
任意の数の値を関数に渡したいことがある。例えば、数値を要素とするリストをsum関数に渡して、要素の合計を計算したいといった場合だ。以下に例を示す。
int_list = [2, 1, 9, 7, 3]
result = sum(int_list)
print(result) # 22
このような可変長の値を受け取る関数を自分で定義するには「可変長引数」を使用する。可変長引数にも位置引数とキーワード引数の両者を受け取るための仕組みが用意されている。前者を可変長位置パラメーターと、後者を可変長キーワードパラメーターと呼ぶことにしよう。
パラメーターリストの中でパラメーター名の前に「*」を置くことで、それが可変長位置パラメーターとなる。変数名としては「args」を使うのが慣例であり、推奨されてもいる。つまり、パラメーターリストの中に「*args」とあれば、それは可変長位置引数を受け取るものである(なお、1つのパラメーターリストの中で可変長位置パラメーターを複数置くことはできない)。
可変長位置パラメーターは、その関数が受け取れる位置引数から溢れたものを全て受け取り、タプルに格納する。以下に例を示す。
def varpos(a, b, *args): # argsにはa、bが受け取ったもの以外が渡される(タプル)
print(f'a: {a}, {b}, args: {args}')
varpos(1, 2, 3, 4, 5) # a: 1, 2, args: (3, 4, 5)
この例では位置引数もしくはキーワード引数を受け取るパラメーターが2つあり、その後に「*args」がある。この関数を呼び出す際に3つ以上の位置引数が渡されると、最初の2つの値がパラメーターaとbに代入され、あまったものはargsが全て受け取るということだ。
そのため、上の呼び出し「varpos(1, 2, 3, 4, 5)」では1がパラメーターaに、2がパラメーターbに渡され、残る3つの値はargsに渡される。出力結果を見ると、argsがこれら3つの値を要素とするタプルとなっていることが分かる。
下の呼び出しでは、タプル「(3, 4, 5)」が可変長位置引数としてパラメーターargsに渡されるが、これは3つの要素を含んだタプルではなく、「((3, 4, 5),)」のように「3つの要素を含んだタプルを格納するタプル」となっていることに注目されたい。
varpos(1, 2, (3, 4, 5)) # a: 1, 2, args: ((3, 4, 5),)
そうではなく、タプルやリストをアンパックして関数に渡す必要がある、つまり「varpos(1, 2, (3, 4, 5))」を「varpos(1, 2, 3, 4, 5)」のようにしたいのであれば、単項の「*」演算子を展開したい反復可能オブジェクトに前置する。例えば、「varpos(1, 2, *(3, 4, 5))」とすれば、タプル「(3, 4, 5)」がアンパックされて関数に渡される、つまり「varpos(1, 2, 3, 4, 5)」として呼び出されるということだ。
以下はリストをアンパックして、varpos関数に渡す例だ。
lst = [1, 2, 3, 4, 5]
varpos(*lst) # a: 1, 2, args: (3, 4, 5)
引数は1つだけのように見えるが、「*」がリストに前置されているので、リストがアンパックされて、5つの要素が個別に関数に渡される。そのため、最初の2つがパラメーターaとbに、残りがargsに代入される。
キーワード引数についても同様な仕組みがある。ただし、可変長キーワードパラメーターについては「*」ではなく「**」を使用する。パラメーターリスト中で特定のパラメーターの前に「**」を置くことで、そのパラメーターは可変長のキーワード引数を受け取るようになる。このとき、パラメーター名には「kwargs」を使うことが慣例的で、そうすることが推奨されている。このとき、kwargsには辞書を使って「{'keyword0': value0, 'keyword1': value1, ……}」のような形式でキーワード引数に指定したキーワードとその値が格納される。
以下に例を示す。
def varkwd(*, a, b, **kwargs):
print(f'a: {a}, b: {b}, kwargs: {kwargs}')
varkwd(b=2, a=1, d=4, c=3) # a: 1, b: 2, kwargs: {'d': 4, 'c': 3}
この例では、パラメーターaとbの前に「*」があるので、全てのパラメーターがキーワード引数のみを受け付けることが分かる。そして、aとbの後に「**kwargs」があるので、「a=…」「b=…」以外のキーワード引数は全てkwargsに辞書として格納される。
その下の呼び出しではパラメーターaとbに加えて、「d=4」「c=3」とキーワード引数を使って値が渡されている。そのため、これら2つのキーワード引数がkwargsに格納される。
可変長位置引数と同様、可変長キーワード引数もアンパックして関数に渡せる。これには単項の「**」演算子を辞書の前に置けばよい。以下に例を示す。
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
varkwd(**d) # a: 1, b: 2, kwargs: {'c': 3, 'd': 4}
この例では、辞書dに4つの項目が含まれている。そして、varkwd関数呼び出しではその辞書の前に「**」を前置することで、辞書がアンパックされて関数に渡されている(そのため、結果は上と同じになる)。
可変長位置パラメーターと可変長キーワードパラメーターを混在させることも可能だ。このときには、可変長位置パラメーターを可変長キーワードパラメーターよりも先に置く必要がある点には注意しよう。また、呼び出し時には位置引数をキーワード引数よりも先に記述する必要もある。
以下に例を示す。
def varargs(a, b, *args, **kwargs):
print(f'a: {a}, b: {b}, args: {args}, kwargs{kwargs}')
varargs(1, 2, 3, d=4, e=5) # a: 1, b: 2, args: (3,), kwargs{'d': 4, 'e': 5}
この例では、パラメーターaとbに続けて、可変長位置引数を受け取るargsと可変長キーワード引数を受け取るkwargsがパラメーターリストに含まれている。そして、この関数を「varargs(1, 2, 3, d=4, e=5)」として呼び出すと、最初の2つの引数がパラメーターaとbに順番に渡されて、3つ目の位置引数はargsに渡され、残ったキーワード引数がkwargsに渡される。
Copyright© Digital Advantage Corp. All Rights Reserved.