Python デフォルト引数の注意点

Python学習【365日チャレンジ!】50日目のマスターU(@Udemy11)です。

やっぱり一の位が0になるとなんとなく嬉しくなっちゃいますね。それに50は100の半分なので、ちょっとした区切りのようにも感じます。

ここで気を緩めずに、しっかりと継続してPythonを学習していきますよ!

昨日の復習

昨日は、関数のキーワード引数、位置引数、デフォルト引数について学習しました。

デフォルト引数を定義しておけば、実行時に引数の値を指定しなくてもデフォルト引数が代入されました。

def cal(year='2020', month='Jan', day='1'):
    print(year, month, day)
 
cal()

出力結果

2020 Jan 1

キーワード引数は、記載順が違っても、キーワードを判断して、値を代入してくれました。

def cal(year='2020', month='Jan', day='1'):
    print(year, month, day)
 
cal(day='20', year='2019', month='Nov')

出力結果

2019 Nov 20

キーワード引数と位置引数は合わせても使えますが、位置引数を使う場合は、最初の位置から使う必要があって、1番目にキーワード引数を指定したら、2番目以降に位置引数を入れるとエラーが起こりました。

次のような代入の仕方だとエラーが起こります。

cal(year='2019', month='Mar', '11')
info(year='2019', 'Mar', '11')
info('2019', month='Mar', '11')
info(year='2019', '11', month='Mar')
info('2019', year='2018', day='11')

Pythonが処理をする段階で、引数の位置がわからなくなったり、値が重複してしまったりすることでエラーが起こってしまいます。

位置引数を使用する場合は最初の位置から使うようにしましょう。

デフォルト引数にリストを使う場合

デフォルト引数は実行時に値を指定しなくても値が代入されてエラーを回避できるので、非常に便利なのですが、使い方に注意が必要です。

デフォルト引数に空のリストを使うときを考えてみます。

def cal_func(a, l=[]):
    l.append(a)
    return l
 
r = cal_func(10)
print(r)

出力結果

[10]

このコードは、関数cal_funcを変数aと空のリストlを指定し、リストlに変数aを追加したリストlを返り値に定義しています。

実行は、変数aに10を代入しているので、lには、デフォルト引数である空のリストが代入されて、10が追加されたリスト[10]が返されますので、出力は[10]となります。

次は、関数実行時にリストに値を入れてみるとどうなるでしょう。

def cal_func(a, l=[]):
    l.append(a)
    return l
 
r = cal_func(10, [1, 2, 3])
print(r)

この場合、位置引数として変数aに10、リストlに[1, 2, 3]が代入されるので、返り値は変数aの値10が追加されたリスト[1, 2, 3, 10]となります。

出力結果

[1, 2, 3, 10]

ここまでは全く問題はないのですが、次のような実行をすると、もともとの関数定義が変わってくるので、問題が起こってきます。

def cal_func(a, l=[]):
    l.append(a)
    return l
 
r = cal_func(10)
print(r)
 
s = cal_func(10)
print(s)

出力結果

[10]
[10, 10]

通常なら、関数cal_funcを何度実行しても、2番めの引数を指定していなければ、デフォルト引数である空のリスト[]が代入されるはずなので、どちらの結果も[10]が返されるはずですが、2回めの実行時には、[10, 10]という出力になっています。

これは以前学習した、リストは参照渡しになるということが関係しています。

参照渡しの場合、値を代入したときに元の値が変えられてしまうので、最初に指定している空のリストlの値が変更されてしまいます。

つまり、関数cal_funcを引数lのリストに値を入れずにデフォルト引数である空のリストを使うことで、実行されたあとの引数(値が入ったリスト)がデフォルト引数に置き換わってしまうということです。

この場合、最初の関数実行のあとで、デフォルト引数が[10]になり、2回めの関数実行のあとには[10, 10]になってしまっているということです。

参照渡しはデフォルト引数に使わない

つまり、参照渡しになるリストや辞書型をデフォルト引数で使うとバグにつながるので、基本的に参照渡しの型はデフォルト引数に使わないようにします。

ただ、関数に空のリストを入れて処理するという作業はよく使われるので、空のリストをデフォルト引数にするのではなく、Noneタイプを指定して、関数の中で、実行時に引数が指定されなかった場合に空のリストを入れるコードを書くようにします。

def l_func(a, l=None):
    if l is None:
        l = []
    l.append(a)
    return l
 
r = l_func(100)
print(r)
 
s = l_func(100)
print(s)

出力結果

[100]
[100]

どちらの実行も、関数l_funcの実行時にlの引数が入っていない(None)ので、lには空のリストが代入されて変数aが追加されたリストが返り値になります。

じっくり学ぶならUdemy

ほんとこれはつくづく感じているところです。

何度も復習しながら、講座をすすめていますが、しれっと前にやったことが入ってくるので、それを思い出すまでにある程度のタイムラグが生じます。

講座は、そんなタイムラグを待ってはくれないので、必ず講座をストップして過去のレクチャーを復習したり、頭の中で思い出したりしながら、理解できた時点で講座を再開するようにしています。

普通に講座を進めてしまうと、理解できないことがどんどん積み上がっていくので、何度も繰り返し復習しないとわからないことだらけになって、講座を受講し終えたとしても、結局重要なことは身についていないなんてことになりかねません。

例えば、スクール形式の講座の場合は、わからないことがあっても講座はどんどん進んでしまいます。

学校の授業できちんと理解できていない子どもたちが取り残されてしまうように、スクール形式の講座は理解できない人は取り残されてしまいますし、そこで質問ができたとしても、たくさんの人がいる中で、質問すること自体がハードルが高すぎます。

一方で、オンライン講座のUdemyの場合は、いつでもレクチャーを止めて何度も繰り返して学習することができるうえ、理解できなかったことは、いつでも講師に質問することが可能です。

Udemyは、学びたい人にとって、最高の学習プラットフォームであり、Udemyほど時代にマッチしたサービスは見当たりません。

Udemyには、100,000以上の講座が登録されているので、Python学習だけでなく、あなたが学びたい講座がきっと見つかるはずです。

ぜひUdemyで魅力的な講座を見つけてください。

↓公式サイトはこちら↓
UdemyセールUdemyセール

最後は、ちょっとUdemyの紹介になってしまいましたが、明日もしっかりPythonを学習しますよ!

それでは、明日もGood Python!