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

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

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

このエントリでは、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では、デフォルト引数は呼び出し毎に定義されます。

[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
=> []

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

以上です。

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

Thank you!
Thank you!
URLをコピーしました

コメントを送る

コメントはブログオーナーのみ閲覧できます