사전을 복사하고 사본 만 편집하는 방법
누군가 나에게 이것을 설명해 주시겠습니까? 이것은 나에게 의미가 없습니다.
사전을 다른 사전으로 복사하고 두 번째를 편집하면 둘 다 변경됩니다. 왜 이런 일이 발생합니까?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
파이썬은 결코 암시 적으로 객체를 복사 하지 않습니다 . 을 설정하면 dict2 = dict1
정확히 동일한 dict 객체를 참조하게되므로 변경하면 해당 객체에 대한 모든 참조가 현재 상태의 객체를 계속 참조합니다.
드물게 dict를 복사하려면 다음을 사용하여 명시 적으로 수행해야합니다.
dict2 = dict(dict1)
또는
dict2 = dict1.copy()
당신이 할당 할 때 dict2 = dict1
, 당신의 사본을 제작하지 않습니다 dict1
, 그것은 결과를 dict2
위한 또 다른 이름 인 dict1
.
사전과 같은 가변 유형을 복사하려면 모듈의 copy
/ deepcopy
를 사용 하십시오 copy
.
import copy
dict2 = copy.deepcopy(dict1)
dict.copy()
및 dict(dict1)
복사본을 생성하는 동안 얕은 복사본 일뿐 입니다. 깊은 복사 를 원하면 copy.deepcopy(dict1)
이 필요합니다. 예 :
>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10 # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40 # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3 # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
얕은 사본과 깊은 사본과 관련하여 Python copy
모듈 문서에서 :
얕은 복사와 전체 복사의 차이는 복합 객체 (목록 또는 클래스 인스턴스와 같은 다른 객체를 포함하는 객체)에만 해당됩니다.
- 단순 복사는 새로운 복합 객체를 생성 한 다음 가능한 한 원본에서 발견 된 객체에 대한 참조를 여기에 삽입합니다.
- 전체 복사는 새로운 복합 개체를 생성 한 다음 재귀 적으로 원본에있는 개체의 복사본을 삽입합니다.
파이썬 3.5 이상에서는 ** unpackaging 연산자를 사용하여 얕은 사본을 얻는 더 쉬운 방법이 있습니다. Pep 448에 의해 정의되었습니다 .
>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}
** 딕셔너리를 새 딕셔너리로 압축 해제 한 다음 dict2에 할당합니다.
또한 각 사전에 고유 한 ID가 있는지 확인할 수도 있습니다.
>>>id(dict1)
178192816
>>>id(dict2)
178192600
깊은 복사가 필요한 경우 copy.deepcopy () 는 여전히 갈 길입니다.
Python 2.7과 3 모두 에서 dict 사본 을 만드는 가장 쉽고 쉬운 방법 은 다음 과 같습니다.
단순 (단일 수준) 사전의 복사본을 만들려면 :
1. 사용 딕셔너리 () 메소드를 대신 기존 딕셔너리를 가리키는 레퍼런스를 생성하는 단계를 포함한다.
my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1) # {'message':'Hello Python'}
my_dict2 = dict(my_dict1)
print(my_dict2) # {'message':'Hello Python'}
# Made changes in my_dict1
my_dict1["name"] = "Emrit"
print(my_dict1) # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2) # {'message':'Hello Python'}
2. 파이썬 사전에 내장 된 update () 메소드 사용.
my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2) # {'message':'Hello Python'}
# Made changes in my_dict1
my_dict1["name"] = "Emrit"
print(my_dict1) # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2) # {'message':'Hello Python'}
중첩되거나 복잡한 사전의 복사본을 만들려면 :
일반 얕은 및 전체 복사 작업을 제공하는 기본 제공 복사 모듈을 사용합니다 . 이 모듈은 Python 2.7 및 3 * 모두에 있습니다.
import copy
my_dict2 = copy.deepcopy(my_dict1)
사전 이해력으로 새 사전을 만들 수도 있습니다. 이렇게하면 복사본을 가져 오지 않습니다.
dout = dict((k,v) for k,v in mydict.items())
물론 파이썬> = 2.7에서는 다음을 수행 할 수 있습니다.
dout = {k:v for k,v in mydict.items()}
그러나 이전 버전과의 호환성의 경우 최상위 방법이 더 좋습니다.
제공된 다른 솔루션 외에도 **
사전을 빈 사전에 통합하는 데 사용할 수 있습니다 .
shallow_copy_of_other_dict = {**other_dict}
.
이제 "얕은"복사본을 갖게됩니다 other_dict
.
귀하의 예에 적용 :
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>
Python의 할당 문은 개체를 복사하지 않으며 대상과 개체 사이에 바인딩을 만듭니다.
따라서 와 참조 하는 객체 dict2 = dict1
사이에 또 다른 바인딩이 발생 합니다.dict2
dict1
dict를 복사하려면 copy module
. 복사 모듈에는 두 가지 인터페이스가 있습니다.
copy.copy(x)
Return a shallow copy of x.
copy.deepcopy(x)
Return a deep copy of x.
얕은 복사와 전체 복사의 차이는 복합 객체 (목록 또는 클래스 인스턴스와 같은 다른 객체를 포함하는 객체)에만 해당됩니다.
얕은 사본 객체에 그것에 대한 참조가 원래 발견 삽입 (가능한 범위까지) 한 후 새로운 화합물 및 객체를 구성한다.
전체 복사 는 새로운 복합 개체를 생성 한 다음 재귀 적으로 원본에있는 개체의 복사본을 삽입합니다.
예를 들어 python 2.7.9에서 :
>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')
결과는 다음과 같습니다.
>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]
You can copy and edit the newly constructed copy in one go by calling the dict
constructor with additional keyword arguments:
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
This confused me too, initially, because I was coming from a C background.
In C, a variable is a location in memory with a defined type. Assigning to a variable copies the data into the variable's memory location.
But in Python, variables act more like pointers to objects. So assigning one variable to another doesn't make a copy, it just makes that variable name point to the same object.
Every variable in python (stuff like dict1
or str
or __builtins__
is a pointer to some hidden platonic "object" inside the machine.
If you set dict1 = dict2
,you just point dict1
to the same object (or memory location, or whatever analogy you like) as dict2
. Now, the object referenced by dict1
is the same object referenced by dict2
.
You can check: dict1 is dict2
should be True
. Also, id(dict1)
should be the same as id(dict2)
.
You want dict1 = copy(dict2)
, or dict1 = deepcopy(dict2)
.
The difference between copy
and deepcopy
? deepcopy
will make sure that the elements of dict2
(did you point it at a list?) are also copies.
I don't use deepcopy
much - it's usually poor practice to write code that needs it (in my opinion).
dict2 = dict1
does not copy the dictionary. It simply gives you the programmer a second way (dict2
) to refer to the same dictionary.
dict1
is a symbol that references an underlying dictionary object. Assigning dict1
to dict2
merely assigns the same reference. Changing a key's value via the dict2
symbol changes the underlying object, which also affects dict1
. This is confusing.
It is far easier to reason about immutable values than references, so make copies whenever possible:
person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26} # does not mutate person dict
This is syntactically the same as:
one_year_later = dict(person, age=26)
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1
There are many ways to copy Dict object, I simply use
dict_1 = {
'a':1,
'b':2
}
dict_2 = {}
dict_2.update(dict_1)
Because python works with reference, so when you did dict2 = dict1 you pass a reference to dict2, that was the same as dict1. So, when you make a change in dict1 or dict2 you change a reference, and both dicts chages. Sorry if I mistake something on English.
As others have explained, the built-in dict
does not do what you want. But in Python2 (and probably 3 too) you can easily create a ValueDict
class that copies with =
so you can be sure that the original will not change.
class ValueDict(dict):
def __ilshift__(self, args):
result = ValueDict(self)
if isinstance(args, dict):
dict.update(result, args)
else:
dict.__setitem__(result, *args)
return result # Pythonic LVALUE modification
def __irshift__(self, args):
result = ValueDict(self)
dict.__delitem__(result, args)
return result # Pythonic LVALUE modification
def __setitem__(self, k, v):
raise AttributeError, \
"Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)
def __delitem__(self, k):
raise AttributeError, \
"Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)
def update(self, d2):
raise AttributeError, \
"Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""
# test
d = ValueDict()
d <<='apples', 5
d <<='pears', 8
print "d =", d
e = d
e <<='bananas', 1
print "e =", e
print "d =", d
d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']
# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1
# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."
Please refer to the lvalue modification pattern discussed here: Python 2.7 - clean syntax for lvalue modification. The key observation is that str
and int
behave as values in Python (even though they're actually immutable objects under the hood). While you're observing that, please also observe that nothing is magically special about str
or int
. dict
can be used in much the same ways, and I can think of many cases where ValueDict
makes sense.
Nice explanations, I want to add the simplest rule you can refer to when thinking of Python variables which you assign equal with =
. If the data type is immutable, you don't have to worry about the unexpected behavior you encountered. If the data type is mutable, you want to make sure you make a copy of it to prevent the unexpected behavior your encountered.
Immutable data types: string (a tuple of characters), tuple
Mutable data types: list, array, dictionary
because, dict2 = dict1, dict2 holds the reference to dict1. Both dict1 and dict2 points to the same location in the memory. This is just a normal case while working with mutable objects in python. When you are working with mutable objects in python you must be careful as it is hard to debug. Such as the following example.
my_users = {
'ids':[1,2],
'blocked_ids':[5,6,7]
}
ids = my_users.get('ids')
ids.extend(my_users.get('blocked_ids')) #all_ids
print ids#output:[1, 2, 5, 6, 7]
print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}
This example intention is to get all the user ids including blocked ids. That we got from ids variable but we also updated the value of my_users unintentionally. when you extended the ids with blocked_ids my_users got updated because ids refer to my_users.
the following code, which is on dicts which follows json syntax more than 3 times faster than deepcopy
def CopyDict(dSrc):
try:
return json.loads(json.dumps(dSrc))
except Exception as e:
Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
return deepcopy(dSrc)
You can use directly:
dict2 = eval(repr(dict1))
where object dict2 is an independent copy of dict1, so you can modify dict2 without affecting dict1.
This works for any kind of object.
참고URL : https://stackoverflow.com/questions/2465921/how-to-copy-a-dictionary-and-only-edit-the-copy
'programing tip' 카테고리의 다른 글
SQL Server의 DateTime2 대 DateTime (0) | 2020.09.30 |
---|---|
JavaScript로 브라우저 뷰포트 크기 가져 오기 (0) | 2020.09.30 |
JavaScript에 제공된 범위 내에서 범위를 생성하는 "range ()"와 같은 메서드가 있습니까? (0) | 2020.09.30 |
Android에서 지연 후 메서드를 호출하는 방법 (0) | 2020.09.30 |
Markdown 파일의 GitHub 상대 링크 (0) | 2020.09.30 |