Pythonで関数のデフォルトパラメータとしてリストなどの可変タイプを使用する場合の問題と解決策


文書ディレクトリ
  • 一、現象説明
  • 二、原因分析
  • 三、解決策
  • 四、参考資料
  • Pythonの初心者は、関数のデフォルトパラメータとして可変タイプ(例えば、listdict)オブジェクトを使用しようとし、関数内部でデフォルトパラメータを変更しようとすると、プログラムの実行結果が予想とは異なる(初心者が予想した結果と解釈器が実行した実際の結果を後述する).この文書では、関数のデフォルトパラメータとして可変タイプを使用する方法について説明します.
  • が引き起こす可能性のある問題.
  • 問題が発生した原因;
  • 問題を解決する方法.

  • 一、現象説明
    上記の問題をより直感的に理解するために、mutable_default()関数を定義するときにパラメータlstを宣言し、その値を空のリスト[]に設定するコードを参照してください.この関数を呼び出し、lstパラメータのデフォルト値を使用するたびに、[1]が得られます.
    def mutable_default(lst=[]):
        lst.append(1)
        return lst
    
    
    def main():
        print(mutable_default())  # 1.   lst      ,     [1]
        print(mutable_default())  # 2.   lst      ,     [1]
        print(mutable_default())  # 3.   lst      ,     [1]
        print(mutable_default(lst=[3, 2]))  # 4.          lst    lst
    
    
    if __name__ == '__main__':
        main()
    
    

    上記のコードの実行結果は次のとおりです.
    [1] [1, 1] [1, 1, 1] [3, 2, 1]
    上記の運転結果より、
  • 関数mutable_default()が複数回呼び出され、毎回パラメータのデフォルト値が使用されると、[1]が最初に返された以外は、後に前回返されたリストの後に1が追加される.
  • 関数mutable_default()が呼び出されるが、パラメータのデフォルト値が使用されない場合、プログラムの実行結果は予想と一致する.

  • 二、原因分析
    このような現象は、デフォルトパラメータが可変タイプの場合、パラメータのデフォルト値がdef文を実行するたびに初期化および保存されるだけで、関数呼び出しのたびに一度も発生しないため、デフォルトパラメータを複数回使用して関数を呼び出すと、パラメータの状態は変わらないためです.
    したがって、mutable_default()が実行されるたびに、lstの最後に1が追加される.なぜなら、lst変数は、デフォルトパラメータを使用して関数を呼び出すたびに、同じオブジェクトであるデフォルトの空のリスト[]を指すからである.
    三、解決方案
    上記の現象があなたが望んでいない場合は、このような方法で回避することができます.
  • lstのデフォルト値をNoneに設定します.
  • は、関数の内部でlstを空のリストに向けさせる.
  • def mutable_default(lst=None):
        if lst is None:
            lst = []
        lst.append(1)
        return lst
    
    
    def main():
        print(mutable_default())  # 1.   lst      ,     [1]
        print(mutable_default())  # 2.   lst      ,     [1]
        print(mutable_default())  # 3.   lst      ,     [1]
        print(mutable_default(lst=[3, 2]))  # 4.          lst    lst
    
    
    if __name__ == '__main__':
        main()
    
    

    上記のコードの実行結果は次のとおりです.
    [1] [1] [1] [3, 2, 1]
    実際、Pythonの関数パラメータのデフォルト値は__defaults__という属性に保存されていますが、この属性は次のようにメタグループです.
    def mutable_default(lst=None, dct=None):
        if lst is None:
            lst = []
        if dct is None:
            dct = {}
        lst.append(1)
        return lst
    
    
    def main():
        print(mutable_default.__defaults__)
    
    
    if __name__ == '__main__':
        main()
    
    

    上記のコードの実行結果は次のとおりです.
    (None, None)
    メタグループには一般的に様々な可変タイプが保存されているため、この特徴は、関数パラメータのデフォルト値を可変タイプにしないほうがいい理由を記憶するのに役立ちます.
    四、参考資料
  • [1] Using a mutable default value as an argument
  • [2] Stack Overflow - Hidden features of Python
  • [3] How to Use the Python or Operator