引数にデフォルト値を設定する

引数を受け取るように設定した関数で、仮引数に対してデフォルト値を設定しておくと関数を呼び出す時に引数を省略することができます。ここでは引数にデフォルト値を設定する方法について解説します。

(Last modified: )

引数にデフォルト値を設定する

関数を定義するときに引数にデフォルト値を設定することができます。デフォルト値が設定されていると関数の呼び出しが行われた時に引数が省略されると代わりにデフォルト値が使用されます。

引数にデフォルト値を設定する場合は次のように記述します。

def 関数名(引数 = デフォルト値):
    関数内で実行する処理

    return 戻り値

関数を呼び出す時に、引数をを指定していればその値が使用され、引数が省略された場合はデフォルト値が代わりに使用されます。

サンプルコード

次のサンプルを見て下さい。

def myfunc(msg = "Hello"):
    print(msg)

myfunc("こんにちは")
>> こんにちは

myfunc()
>> Hello

引数のデフォルト値として "Hello" を設定しています。関数を呼び出す時に引数を指定した場合はその値が使用されますが、引数を省略した場合はデフォルト値が実引数の代わりに仮引数に代入されて使用されます。

複数の引数にデフォルト値を設定する場合の注意点

複数の引数がある場合、それぞれにデフォルト値を設定することができます。また一部の引数にだけデフォルト値を設定することができます。ただし複数の引数がある場合に一部の引数にだけデフォルト値を設定する場合、デフォルト値のない引数がデフォルト値のある引数よりも後に記述することはできません。

次のようにすべての引数にデフォルト値を設定するか、デフォルト値が設定されている引数がデフォルト値が設定されていない引数よりも後に定義されている場合は問題ありません。

 全ての引数にデフォルト値を設定する
def 関数名(引数1 = デフォルト値1, 引数2 = デフォルト値2):
    return

関数名(n1, n2)
関数名(n1)
関数名()

 二番目の引数にだけデフォルト値を設定する
def 関数名(引数1, 引数2 = デフォルト値2):
    return

関数名(n1, n2)
関数名(n1)

デフォルト値が設定されていない引数がある場合には、必ずその分は実引数を指定して関数を呼び出す必要があります。

次のようにデフォルト値が設定されている引数がデフォルト値が設定されてない引数よりも前に定義されている場合はエラーとなります。

 一番目の引数にだけデフォルト値を設定する
def 関数名(引数1 = デフォルト値1, 引数2):
    return

 三つある引数の二番目の引数にだけデフォルト値を設定する
def 関数名(引数1, 引数2 = デフォルト値2, 引数3):
    return

次の例を見てください。一番目の引数にだけデフォルト値を設定して関数を定義しようとすると SyntaxError エラーとなります。

def myfunc(n1 = 10, n2):
    return

>>   File "<stdin>", line 1
>> SyntaxError: non-default argument follows default argument
サンプルコード

次のサンプルを見てください。

def myfunc(num1, str1 = "未入力", str2 = "不明"):
    print("年齢は" + str(num1) + "です。", end='')
    print("名前は" + str1 + "です。", end='')
    print("住所は" + str2 + "です。")

myfunc(28, "Suzuki", "Tokyo")
>> 年齢は28です。名前はSuzukiです。住所はTokyoです。

myfunc(25, "Yamada")
>> 年齢は25です。名前はYamadaです。住所は不明です。

myfunc(30)
>> 年齢は30です。名前は未入力です。住所は不明です。

引数が 3 つあり、二番目と三番目の引数にはデフォルト値が設定されています。関数を呼び出す時に引数を省略すると、デフォルト値が代わりに使用されます。

デフォルト値にリストなどのミュータブルオブジェクトを設定する場合の注意点

デフォルト値を使用する場合でもう一つ注意すべき点が、デフォルト値の評価は関数の定義が行われる時に一度だけしか行われないという点です。

例えば次のような関数を定義したとします。

def myfunc(num1, num2 = 10):
    num2 *= 2
    print(num1 + num2)

myfunc(5)
myfunc(7)

引数の num2 にはデフォルト値として 10 が設定されています。関数を呼び出すときに 2 番目の引数を省略すると、関数側で仮引数の変数 num2 にデフォルト値の 10 が代入されるのですが、関数が呼ばれるたびにこの代入が行われるのではなく、関数が定義された時に一度だけ行われます。

より具体的には関数が定義された時にデフォルト値として設定した 10 という値が保管されている場所を変数 num2 が参照するように設定されます。そして関数が呼び出されるたびにこの設定が毎回適用されます。つまり毎回 num2 は関数の定義時にデフォルト値が保管された同じ場所を参照します。

デフォルト値が数値や文字列のような一度作成すると変更できないイミュータブルなオブジェクトの場合、関数の中で変数 num2 に違う値を代入すると、もともと 10 というデフォルト値が保管された場所の値を書き換えるのではなく、新しい場所に新しい値を保管した上で変数 num2 が参照するようになるのでもともと 10 というデフォルト値が保管された場所の値は変わりません。その為、再び関数が呼び出されると変数 num2 は常に最初と同じ場所を参照し 10 という値を持ちます。

このようにデフォルト値がイミュータブルなオブジェクトの場合はあまり気にされる必要はないのですが、デフォルト値がリストなどのミュータブルなオブジェクトの場合は注意が必要です。例えば次のような関数を定義したとします。

def myfunc(str1, list1 = ["a"]):
    list1.append(str1)
    return list1

myfunc("b")
myfunc("c")
myfunc("d")

引数の list1 にはデフォルト値としてリストのオブジェクトである ["a"] が設定されています。この場合も同じように関数を定義した時に一度だけ評価が行われます。具体的にはデフォルト値として ["a"] という値が保管されている場所を変数 list1 が参照するにように設定されます。そして関数が呼び出される時にこの設定が毎回適用されます。つまり毎回 list1 は関数の定義時にデフォルト値が保管された同じ場所を参照します。

デフォルト値がリストのようなミュータブルなオブジェクトの場合、関数の中で変数 list1 に対して要素を追加するなど変更を加えると、もともと ["a"] というデフォルト値が保管された場所の値が書き換えられます。再び関数が呼び出されると変数 list1 は常に最初と同じ場所を参照するため書き換えられた値を持ってしまいます。

先ほどの例を実際に試してみると次のような結果となります。

def myfunc(str1, list1 = ["a"]):
    list1.append(str1)
    return list1

myfunc("b")
>> ['a', 'b']
myfunc("c")
>> ['a', 'b', 'c']
myfunc("d")
>> ['a', 'b', 'c', 'd']

関数を呼び出すたびに、引数の list1 に ["a"] というデフォルト値が代入されるわけではなく、同じ場所に保管されている値を関数を呼び出すたびに変更を加えています。もちろん仕様を理解した上でこのように動作させることを目的としている場合はいいのですが、そうではなく毎回初期化が行われるものと想定していると想定外の結果となるため注意が必要です。

なおリストのようなミュータブルなオブジェクトを毎回初期化して利用したい場合は、次のようにプログラムを変更するように公式サイトでは解説しています。

def myfunc(str1, list1 = None):
    if list1 is None:
        list1 = ["a"]
    list1.append(str1)
    return list1

myfunc("b")
>> ['a', 'b']
myfunc("c")
>> ['a', 'c']
myfunc("d")
>> ['a', 'd']

デフォルト値にミュータブルなオブジェクトを指定せずに代わりに None などを指定しておき、関数の処理の中で改めて引数が代入された変数に対して初期値を設定するという方法です。デフォルト値がミュータブルなオブジェクトではないので、関数の中で変更を加えてもデフォルト値が参照する場所の値は変化しません。その為、関数が呼び出されるたびに list1 には None が保管されている場所を参照するように設定されて、結果として毎回初期化が行われます。

-- --

引数にデフォルト値を設定する方法について解説しました。

( Written by Tatsuo Ikura )

Profile
profile_img

著者 / TATSUO IKURA

プログラミングや開発環境構築の解説サイトを運営しています。