↓ メインコンテンツへスキップ
  1. 第03講 関数(2/2; 関数の応用)/

関数(2/2) 高度な引数の扱い

高度な引数の扱い
#

教科書 p.180(Lesson 7)

前回の資料の通り、基本的には、仮引数と実引数の数は一致している必要があります。 しかし、Pythonでは、以下のような高度な引数の扱いが可能で、この場合、引数の数が一致していなくてもエラーになりません。

デフォルト引数
#

関数定義時に、仮引数にデフォルト値を設定することができます。 実引数が与えられなかった場合のデフォルト値を指定できることになります。

def print_sales_tax(price, is_reduced_tax_rate = False):
    if is_reduced_tax_rate:
        print(f"{price}円 消費税(軽減税率): {price * 0.08} 円、小計: {price * 1.08} 円")
    else:
        print(f"{price}円 消費税: {price * 0.1} 円、小計: {price * 1.1} 円")

この場合、呼び出すときに is_reduced_tax_rate を指定しない場合は、False がデフォルトで設定されます。

>>> print_sales_tax(1000)        # is_reduced_tax_rate が指定されていないので False になる。
1000円 消費税: 100.0 円、小計: 1100.0 円
>>> print_sales_tax(1000, False) # 上の例は、このように呼び出したとの同じ結果になる。
1000円 消費税: 100.0 円、小計: 1100.0 円
>>> print_sales_tax(1000, True)  # 指定された値(True)になる。
1000円 消費税(軽減税率): 80.0 円、小計: 1080.0 円

デフォルト引数を指定したい場合、デフォルト引数を持たない引数よりも後ろ(右側)に記述する必要があります。

# このデフォルト引数の指定ではエラーになる。
def func1(a, b = 0, c, d = 1, e): # エラー。e がデフォルト引数になっていない。
    ...

# デフォルト引数は、後ろ側(右側)に集めておく必要がある。
def func2(a, b, c, d = 1, e = 2): # 正しい
    ... 

デフォルト引数のNoneでの初期化
#

デフォルト引数を使うとき、デフォルトとなる引数の初期化は関数が呼び出された時ではなく、関数が定義された時に行われる点に注意してください。 以下のような関数を定義し、items をデフォルト引数にした場合を例に考えます。 items = [] は「呼び出しごとに空リストを用意する」ように見えますが、 実際には関数オブジェクトが 1 つのリストを持ち続け、デフォルト値が使われるたびに同じリストが渡されます。

>>> def append_item(item, items = []):   # この [] は def 実行時に 1 回だけ作られる
...     items.append(item)
...     return items
>>> append_item(1)
[1]
>>> append_item(2)      # 空リストから始まるはずが、前回の [1] が残っている
[1, 2]
>>> append_item.__defaults__
([1, 2],)               # 関数がデフォルト値を抱えたまま

このような場合は、デフォルトに何もないことを表す None を使うことが一般的です。 そして、関数の中で毎回itemsに空のリストを代入するようにしましょう。

Noneで初期化して、関数内で空のリストを作成する
>>> def append_item(item, items = None):
...     if items is None:
...         items = []
...     items.append(item)
...     return items

キーワード引数
#

関数を呼び出すときに、仮引数名 = 値 という書き方で、仮引数の名前を指定して、実引数の値を渡すことができます。 これを引数のキーワード指定(キーワード引数)と呼びます。

func2(10, 9, 8, e = 7, d = 6) # キーワード引数

キーワード引数は、デフォルト引数のうちのいくつかに値を渡すときに用いられます。 また、上記の呼び出し例のように、引数の順番を気にせずに指定できるため、関数の引数が多い場合に便利です。

注意点として、デフォルト引数などがない場合は、キーワード引数で指定した引数よりも右の引数は、すべてキーワード指定して呼び出す必要があります。

可変長引数
#

さらに、関数定義時、引数の先頭に * マークを付けると、可変長引数(variadic argument)を受け取る意味になります。 可変長引数とは、引数の数が幾つでも受け取ることができる引数のことです。

# example function of variadic argument
def eva(*args):
    print(args)

eva(1)       # 1つの値でも呼び出せる。
# => (1,)
eva(1, 2, 3) # 3つの値でも呼び出せる。
# => (1, 2, 3)
eva(1, 3, 5, 7, 9) # 値が幾つでも呼び出せる。
# => (1, 3, 5, 7, 9)

また、可変長引数は、キーワード引数と組み合わせて使うこともできます。 引数の前に ** を付けると、可変長キーワード引数(variadic keyword argument)を受け取ることができます。 このときの仮引数はディクショナリとして扱えます。

# example function of variadic argument
def eva2(**dic):
    print(dic)

eva2(a=1)              # キーワード引数で呼び出せる。
# => {'a': 1}
eva2(a=1, b="10", c=8) # 幾つでもキーワード引数で呼び出せる。
# => {'a': 1, 'b': '10', 'c': 8}

可変長引数に渡すリストや辞書
#

可変長引数を受け取る関数に、リストの要素を展開して渡したい場合があります。 しかし、そのまま渡すとリストそのものが1つの引数として渡されてしまいます。 リストの前に * を付けることで、リストの要素を展開して可変長引数の変数に渡すことができます。

>>> def func(*args):
...     print(args)
...
>>> list = [4, 5, 6]
>>> func(list)
([4, 5, 6],)         # リストそのものが1つの引数として渡される。
>>> func(*list)      # リストの要素を展開して渡す。
(4, 5, 6)            # 3つの要素を持つタプルになる。
>>> func([1, 2, 3])  # リストそのものが1つの引数として渡される。
([1, 2, 3],)         # 1つの要素を持つタプルになる。
>>> func(*[1, 2, 3]) # リストの要素を展開して渡す。
(1, 2, 3)            # 3つの要素を持つタプルになる。

また、辞書のキーと値を展開して渡したい場合もあります。 辞書の前に ** を付けることで、辞書のキーと値を展開して関数に渡すことができます。

def self_introduction(name, age):
    print(f"My name is {name}, {age} years old.") # 辞書をアンパックして渡す

keywords = {'name': 'Taro', 'age': 30}
self_introduction(**keywords)  # => My name is Taro, 30 years old.

複数の返り値
#

Pythonでは、複数の返り値を返すことができます。 返り値を複数指定する場合は、return 文に複数の値をカンマで区切って指定します。 複数の値を返しているように見えますが、実は1つのタプルを返しています。