Pythonの付与、スライス、浅いコピーと深いコピーの違い

24969 ワード

原文住所:
  • 個人ブログ:https://vimior.github.io/article/64c62ee2a508219d/
  • 簡書:https://www.jianshu.com/p/5cf2aebdf7c5

  • 前言
    Pythonは高級言語としてC/C++とは大きく異なる.について付与_、スライス、_浅いコピー_および_深いコピー_このブロックは、実際には多くの人がよく知らないので、いくつかのコードで予想外の結果が出やすく、原因を見つけるのも難しいです.本稿では,これらの状況の違いと使用について述べ,できるだけ分かりやすく,下層の実現原理には触れない.
    本明細書のすべてのコードの実行環境は、次のとおりです.
  • オペレーティングシステム:Window 10
  • Pythonバージョン:Python 3.7.0
  • 実行方式:CMDウィンドウ+Pythonインタラクションのコマンドインタラクションモード
  • 割り当て、スライス、コピー
    本明細書では、is演算子を用いて、オブジェクト間の一意のアイデンティティ識別、すなわちidが同じか否かを判断し、isを同一性演算子と呼ぶ
    に値を付ける
    付与値とは、=によって1つの変数の値を別の変数に付与することであり、参照に相当し、ここでの付与値はいくつかの種類に分けることができる.
    ≪割当て|Assignment|oem_src≫:可変オブジェクトの割当て(キャッシュ範囲内)
    プログラムの実行効率を高めるため、Python 3の解析器では整数数字と文字列キャッシュのメカニズムを実現し、
  • 整数値のキャッシュ範囲は_[-5, 256]__,すなわち、変数値が等しく[-5,20]の範囲内のすべての変数が同じ対象である(これは議論があり、[-5,無限大]という文章があるが、実測は[-5,256])
  • 文字列デフォルトキャッシュ長_4096__,すなわち、変数値が等しく、長さが4096以内のすべての文字列変数が同じオブジェクトである(これは議論されているが、多くの文章ではキャッシュ20ビットと呼ばれているが、私は長さ4096と実測している)
  • #      
    str_a = str_b = 'hello' #     str_a = 'hello'   str_b = str_a      
    str_c = 'hello'
    print(str_b is str_a) #   : True
    print(str_c is str_a) #   :True,    True        ,str_c str_a    ,  'hello',    20  
    
    #     
    int_a = int_b = 100 #     int_a = 100   int_b = int_a      
    int_c = 10 * 10
    print(int_b is int_a) #   True
    print(int_c is int_a) #   True,    True      ,  int_c int_a    ,  100,  [-5, 256]   
    

    割り当て:可変オブジェクトの割り当て(キャッシュの範囲外)
    #      
    str_a = str_b = 'a' * 4097 #     str_a = 'a' * 4097   str_b = str_a      
    str_c = 'a' * 4097
    print(str_b is str_a) #   : True
    print(str_c is str_a) #   :False,    False     str_c str_a    ,     4097,         4096
    
    #     
    int_a = int_b = 1000 #     int_a = 100   int_b = int_a      
    int_c = 10 * 10 * 10
    print(int_b is int_a) #   True
    print(int_c is int_a) #   False,    False     int_c int_a    ,  1000,      ]  [-5, 256]
    

    割当て:可変オブジェクトの割当て
    これは完全参照に相当し、「浅いコピーよりも浅いコピー」です.ここではlist_を仮定します.aをリストにしてlist_a list_への付与b、list_を再付与しない限りaまたはlist_b(list_a=xxxまたはlist_b=yyy)アクションは、list_aまたはlist_bによってリストを操作する(追加、削除、変更...)にかかわらず、別のオブジェクトも変更されます(すなわち、list_aおよびlist_bは、割り当て操作を再実行しない場合、常に同じオブジェクトになります).
    list_a = list_b = [1, 2, 3] #     list_a = [1, 2, 3]   list_b = list_a      
    list_c = [1, 2, 3]
    print(list_b is list_a) #   True,  list_a   list_b,    
    print(list_c is list_a) #   False,    list_a     list_c,    
    #   ,     “        ”         ,         ,    
    #                  (               ),                   ,(                   )
    

    スライス
    スライスとは、あるオブジェクトから部分を抽出する操作であり、スライス操作によって得られるオブジェクトと元のオブジェクトは異なるオブジェクトであるが、そのサブエレメントが同じオブジェクトである可能性がある.ここでは、スライスが浅いコピーに相当する場合がいくつかある
    ≪スライス|Slice|oem_src≫:「≪可変オブジェクトであるサブ要素|Yes Operating Subエレメント|oem_src≫」の変更または削除操作は、他のオブジェクトには影響しません.
    list_a = [1, 2, 3, 4]
    list_b = list_a[:] #     
    print(list_b is list_a) #   False,list_a list_b      
    list_a.append(5) #    list_a        
    # list_a[0] = 11 #    list_a         
    # del list_a[-1] #    list_a         
    print(list_a) #   [1, 2, 3, 4, 5]
    print(list_b) #   [1, 2, 3, 4]
    print(list_a is list_b) #   False,       
    

    [スライス](Slice):[可変オブジェクトのサブ要素](Yes Variable Objects)の操作は別のオブジェクトに影響します.
    list_a = [1, 2, [3], 4] #        list_a[2]       
    list_b = list_a[:] #     
    print(list_b is list_a) #   False,list_a list_b      
    list_a[2].append(44) #                ,               
    # list_a[2][0] = 33 #                ,                   ,     list_a    
    # del list_a[2][-1] #                ,                   ,     list_a    
    print(list_) #   [1, 2, [3, 44], 4]
    print(list_b) #   [1, 2, [3, 44], 4]
    print(list_b is list_a) #   False,list_a list_b      
    print(list_a[2] is list_b[2]) #   True,      ,              , list_a[2] list_b[2]      
    
    
    #   :                   ,                ,       ,              ,           
    list_c = list_a[:3] #      ,      list_c[2]       
    print(list_c is list_a) #   False,list_a list_c      
    list_a[2][0] = 33 #            ,              ,     list_a    
    print(list_a) #   [1, 2, [33, 44], 4]
    print(list_c) #   [1, 2, [33, 44], 4]
    print(list_c is list_a) #   False,list_a list_c      
    print(list_a[2] is list_c[2]) #   True,      ,              , list_a[2] list_c[2]      
    

    コピー
    ここでは、上記の付与値およびスライスに対して、copyモジュールによるコピー操作をコピーする
    浅いコピー
    浅いコピー使用_copy.copy(source)__メソッドインプリメンテーション(list.copyなどのオブジェクト自体がcopyメソッドを提供する場合があります)では、コピーされたオブジェクトと元のオブジェクトが同じオブジェクトである可能性があります.コピーされたオブジェクトが可変オブジェクトである場合、そのサブエレメントが同じオブジェクトである可能性があります.
    一、可変オブジェクトに対して浅いコピーを行い、深いコピーに相当し、値付与操作__に類似し、上記の付与説明を参照してください.付与値とは異なり,ここでコピーしたオブジェクトと元のオブジェクトは同じオブジェクトである.
    import copy
    a = 'hello'
    b = copy.copy(a)
    print(b is a) #   True,     
    
    c = 'a' * 4097
    d = copy.copy(c)
    print(d is c) #   True,      ,        ,     ,               (    )     
    

    二、可変オブジェクトの浅いコピーを行い、完全スライスに相当し、得られたオブジェクトと元のオブジェクトは異なるオブジェクトであるが、そのサブ要素は同じオブジェクトである可能性がある
    import copy
    a = [1, [2, [3, [4]]]]
    b = copy.copy(a)
    print(b is a) #   False,                      
    print(b[0] is a[0]) # True,                        ,         
    print(b[1] is a[1]) # True,                        ,          
    #                ,    ,         
    print(b[1][0] is a[1][0]) # True
    print(b[1][1] is a[1][1]) # True
    
    b[0] = 111 #  b[0]    
    b.append(3434) #  b      
    print(a, b) #   a b    
    
    b[1][0] = 22 #     b[1][0]    
    b[1].append(5) #     b[1]      
    print(b[1], a[1]) #    b[1] a[1]       
    

    深いコピー
    深コピー使用_copy.deepcopy(source)__メソッド実装では、コピーされたオブジェクトと元のオブジェクトが同じオブジェクトである可能性があり、コピーされたオブジェクトが可変オブジェクトである場合、そのサブ要素も同じオブジェクトである可能性がありますが、総じて、この2つのオブジェクトは完全に関係なく(自身もサブオブジェクトも完全に関連していません)、1つの操作は別のオブジェクトに影響しません.
    可変オブジェクトの深いコピー
    import copy
    a = 'a' * 10000
    b = copy.deepcopy(a)
    print(b is a) #   True,                      
    

    可変オブジェクトの深いコピー
    import copy
    c = [1, [2, [3, [4]]]]
    d = copy.deepcopy(c)
    print(d is c) #   False,                      
    print(d[0] is c[0]) #   True,                        
    print(d[1] is c[1]) #   False,                        
    #                ,    ,         
    print(d[1][0] is c[1][0]) #   True
    print(d[1][1] is c[1][1]) #   False
    

    まとめ
  • 可変オブジェクトを割り当てるキャッシュメカニズムがあるかどうかによって、同じオブジェクトであるかどうかを決定する
  • .
  • 付与可変オブジェクトは参照に相当し、
  • を完全にコピーしない.
  • スライスは、浅いコピー
  • に相当する.
  • 可変オブジェクトの浅いコピーは、深いコピー
  • に相当する.
  • 可変オブジェクトを浅いコピーし、1つを直接修正すると他のオブジェクトに影響しませんが、その可変サブ要素の修正は別の
  • に影響します.
  • 深いコピーで得られたオブジェクトは元のオブジェクトとは相互に関係なく、1つの変更は他のオブジェクトに影響を及ぼさない.ここでは、任意の変更
  • を指す.