アルパカログ

Webエンジニア兼マネージャーがプログラミングやマネジメント、読んだ本のまとめを中心に書いてます。

Python デフォルト引数の定義タイミングはハマりやすい

f:id:otoyo0122:20200814141856p:plain:w300

言語を問わず、メソッドの引数にデフォルト値を設定しておく「デフォルト引数」はよく使います。

しかしPythonでは、デフォルト引数の定義タイミングはRubyなど他の言語とは異なっており、ハマりポイントとなっています。

このエントリでは、Python特有のデフォルト引数の定義タイミングを紹介します。

Pythonのデフォルト引数

例として、次のようにnumbersというインスタンス変数を持つ適当なクラスを定義します。

引数numbersのデフォルト値は空のリスト[]です。

>>> class Hoge:
...     def __init__(self, numbers=[]):
...             self.numbers = numbers
... 

次に2つのインスタンスを作成し、一方のnumbersには1を追加します。

>>> hoge1 = Hoge()
>>> hoge2 = Hoge()
>>> 
>>> hoge1.numbers.append(1)
>>> hoge1.numbers
[1]

このとき、もう一方のインスタンスのnumbersはどうなるでしょうか?

>>> hoge2.numbers
# どうなるでしょう?

答えはhoge1.numbersと同じ[1]になります。

>>> hoge2.numbers
[1]

オブジェクトIDを見るとその理由がわかります。

>>> id(hoge1.numbers)
4556099720
>>> id(hoge2.numbers)
4556099720

つまり、引数のデフォルト値(今回のケースでは[])は、呼び出し毎に生成されるのではなく、デフォルト引数の定義時に一度だけ生成されていると考えることができます。

呼び出し毎に異なるオブジェクトをデフォルト値として与えたい場合は次のようにします。

>>> class Hoge:
...     def __init__(self, numbers=None):
...             self.numbers = numbers
...             if numbers is None:
...                     self.numbers = []
... 

ちなみにRubyの場合

Rubyでは、デフォルト引数は呼び出し毎に定義されます。

[1] pry(main)> class Hoge
[1] pry(main)*   attr_accessor :numbers
[1] pry(main)*   
[1] pry(main)*   def initialize(numbers: [])
[1] pry(main)*     self.numbers = numbers
[1] pry(main)*   end  
[1] pry(main)* end  
[2] pry(main)> 
[3] pry(main)> hoge1 = Hoge.new
[4] pry(main)> hoge2 = Hoge.new
[7] pry(main)> 
[8] pry(main)> hoge1.numbers.push(1)
=> [1]
[9] pry(main)> hoge1.numbers
=> [1]
[10] pry(main)> hoge2.numbers
=> []

こちらの方が直感的だと思うのは私だけでしょうか...?

以上です。

参考になった方は、ぜひ「はてブ」やSNSでシェアしていただけると嬉しいです。