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インタラクションのコマンドインタラクションモード 割り当て、スライス、コピー
本明細書では、
に値を付ける
付与値とは、
≪割当て|Assignment|oem_src≫:可変オブジェクトの割当て(キャッシュ範囲内)
プログラムの実行効率を高めるため、Python 3の解析器では整数数字と文字列キャッシュのメカニズムを実現し、整数値のキャッシュ範囲は_[-5, 256]__,すなわち、変数値が等しく[-5,20]の範囲内のすべての変数が同じ対象である(これは議論があり、[-5,無限大]という文章があるが、実測は[-5,256]) 文字列デフォルトキャッシュ長_4096__,すなわち、変数値が等しく、長さが4096以内のすべての文字列変数が同じオブジェクトである(これは議論されているが、多くの文章ではキャッシュ20ビットと呼ばれているが、私は長さ4096と実測している)
割り当て:可変オブジェクトの割り当て(キャッシュの範囲外)
割当て:可変オブジェクトの割当て
これは完全参照に相当し、「浅いコピーよりも浅いコピー」です.ここではlist_を仮定します.aをリストにしてlist_a list_への付与b、list_を再付与しない限りaまたはlist_b(list_a=xxxまたはlist_b=yyy)アクションは、list_aまたはlist_bによってリストを操作する(追加、削除、変更...)にかかわらず、別のオブジェクトも変更されます(すなわち、list_aおよびlist_bは、割り当て操作を再実行しない場合、常に同じオブジェクトになります).
スライス
スライスとは、あるオブジェクトから部分を抽出する操作であり、スライス操作によって得られるオブジェクトと元のオブジェクトは異なるオブジェクトであるが、そのサブエレメントが同じオブジェクトである可能性がある.ここでは、スライスが浅いコピーに相当する場合がいくつかある
≪スライス|Slice|oem_src≫:「≪可変オブジェクトであるサブ要素|Yes Operating Subエレメント|oem_src≫」の変更または削除操作は、他のオブジェクトには影響しません.
[スライス](Slice):[可変オブジェクトのサブ要素](Yes Variable Objects)の操作は別のオブジェクトに影響します.
コピー
ここでは、上記の付与値およびスライスに対して、copyモジュールによるコピー操作をコピーする
浅いコピー
浅いコピー使用_copy.copy(source)__メソッドインプリメンテーション(list.copyなどのオブジェクト自体がcopyメソッドを提供する場合があります)では、コピーされたオブジェクトと元のオブジェクトが同じオブジェクトである可能性があります.コピーされたオブジェクトが可変オブジェクトである場合、そのサブエレメントが同じオブジェクトである可能性があります.
一、可変オブジェクトに対して浅いコピーを行い、深いコピーに相当し、値付与操作__に類似し、上記の付与説明を参照してください.付与値とは異なり,ここでコピーしたオブジェクトと元のオブジェクトは同じオブジェクトである.
二、可変オブジェクトの浅いコピーを行い、完全スライスに相当し、得られたオブジェクトと元のオブジェクトは異なるオブジェクトであるが、そのサブ要素は同じオブジェクトである可能性がある
深いコピー
深コピー使用_copy.deepcopy(source)__メソッド実装では、コピーされたオブジェクトと元のオブジェクトが同じオブジェクトである可能性があり、コピーされたオブジェクトが可変オブジェクトである場合、そのサブ要素も同じオブジェクトである可能性がありますが、総じて、この2つのオブジェクトは完全に関係なく(自身もサブオブジェクトも完全に関連していません)、1つの操作は別のオブジェクトに影響しません.
可変オブジェクトの深いコピー
可変オブジェクトの深いコピー
まとめ可変オブジェクトを割り当てるキャッシュメカニズムがあるかどうかによって、同じオブジェクトであるかどうかを決定する .付与可変オブジェクトは参照に相当し、 を完全にコピーしない.スライスは、浅いコピー に相当する.可変オブジェクトの浅いコピーは、深いコピー に相当する.可変オブジェクトを浅いコピーし、1つを直接修正すると他のオブジェクトに影響しませんが、その可変サブ要素の修正は別の に影響します.深いコピーで得られたオブジェクトは元のオブジェクトとは相互に関係なく、1つの変更は他のオブジェクトに影響を及ぼさない.ここでは、任意の変更 を指す.
前言
Pythonは高級言語としてC/C++とは大きく異なる.について付与_、スライス、_浅いコピー_および_深いコピー_このブロックは、実際には多くの人がよく知らないので、いくつかのコードで予想外の結果が出やすく、原因を見つけるのも難しいです.本稿では,これらの状況の違いと使用について述べ,できるだけ分かりやすく,下層の実現原理には触れない.
本明細書のすべてのコードの実行環境は、次のとおりです.
本明細書では、
is
演算子を用いて、オブジェクト間の一意のアイデンティティ識別、すなわちidが同じか否かを判断し、is
を同一性演算子と呼ぶに値を付ける
付与値とは、
=
によって1つの変数の値を別の変数に付与することであり、参照に相当し、ここでの付与値はいくつかの種類に分けることができる.≪割当て|Assignment|oem_src≫:可変オブジェクトの割当て(キャッシュ範囲内)
プログラムの実行効率を高めるため、Python 3の解析器では整数数字と文字列キャッシュのメカニズムを実現し、
#
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
まとめ