IT이야기

사전을 복사하고 사본만 편집하는 방법

cyworld 2022. 3. 22. 21:19
반응형

사전을 복사하고 사본만 편집하는 방법

누가 이것 좀 설명해 줄래?이건 말이 안 돼.

나는 사전을 다른 사전으로 복사하고 두 번째 사전을 편집하고 둘 다 변경된다.왜 이런 일이 생기는 건가요?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

Python은 절대 암묵적으로 사물을 복사하지 않는다.설정할 때dict2 = dict1, 당신은 그것들이 정확히 지시하는 물체를 가리키도록 만들고 있다. 그래서 그것을 변이할 때, 그것에 대한 모든 언급은 그것의 현재 상태의 물체를 계속 언급한다.

받아쓰기를 복사하려면( 드문 경우) 명시적으로 다음 작업을 수행하십시오.

dict2 = dict(dict1)

또는

dict2 = dict1.copy()

할당 시dict2 = dict1, 당신은 복사하지 않는다.dict1, 그 결과.dict2의 다른 이름일 뿐이다.dict1.

사전과 같은 변경 가능한 유형을 복사하려면copy/deepcopy모듈에서.

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 모듈 문서로부터 얄팍한 복사본과 딥 복사본:

얕은 복사 및 깊은 복사 간의 차이는 복합 객체(목록 또는 클래스 인스턴스 같은 다른 객체를 포함하는 객체)에만 관련된다.

  • 얕은 복사본은 새로운 복합 객체를 구성하고 (가능한 범위까지) 원본에서 발견된 객체에 참조를 삽입한다.
  • 딥 카피는 새로운 복합 객체를 구성한 다음, 다시 반복적으로 원본에서 발견된 객체의 복사본을 그 객체에 삽입한다.

심층적이고 기억하기 쉬운 방법:

당신이 받아쓰기2 = 받아쓰기1을 할 때마다, 받아쓰기2는 받아쓰기1을 참조한다.drct1과 drct2는 모두 메모리의 같은 위치를 가리킨다.이것은 비단 비단뱀에서 돌연변이를 일으킬 수 있는 물체로 작업할 때의 일반적인 경우일 뿐이다.python에서 돌연변이 개체를 사용할 때는 디버깅하기 어렵기 때문에 주의해야 한다.

받아쓰2 = 받아쓰1을 사용하는 대신, 당신은 받아쓰2와 받아쓰1을 분리하기 위해 파이썬의 복사 모듈에서 복사(허용 사본)와 딥카피 방법을 사용해야 한다.

올바른 방법은 다음과 같다.

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?"
>>> dict2
{'key1': 'value1', 'key2': 'WHY?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>> 

여러분이 볼 수 있듯이 drct1과 drct2의 ID는 모두 다르며, 이는 둘 다 메모리의 다른 위치를 가리키거나 참조하고 있다는 것을 의미한다.

이 솔루션은 불변의 값이 있는 사전에서 작동하는데, 이것은 변이 가능한 값이 있는 사전에서는 올바른 솔루션이 아니다.

예:

>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960

우리가 받아쓰기를 신청했음에도 불구하고 받아쓰2와 받아쓰1 둘 다에서 돌연변이의 값이 거짓으로 바뀐다는 것을 알 수 있다.이것은 우리가 detc1의 일부분을 detcable의 값을 변경했기 때문이다.우리가 받아쓰기에 복사본을 적용할 때, 그것은 모든 불변의 값을 새로운 받아쓰기에 복사하고, 변이 가능한 값을 복사하지 않고 그것들을 참조하는 것을 의미하는 얕은 복사본만 할 것이다.

궁극적인 해결책은 descript1의 딥 카피를 하여 돌연변이를 포함한 모든 값을 복사한 새로운 명령어를 완전히 만드는 것이다.

>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}

보다시피 id는 서로 다르기 때문에, drct2는 drct1에 있는 모든 값을 가진 완전히 새로운 drcd2라는 것을 의미한다.

원래 명령어에 영향을 미치지 않고 임의의 변이 가능한 값을 변경하고자 할 때마다 딥카피를 사용해야 한다.만약 그렇지 않다면 당신은 얕은 복사본을 사용할 수 있다.딥카피는 원래 명령어에 내포된 값을 복사하는 재귀적으로 작동하고 메모리도 추가로 사용하기 때문에 속도가 느리다.

python 3.5+에서는 ** 포장 풀기 연산자를 사용하여 얕은 복사를 할 수 있는 더 쉬운 방법이 있다.펩 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?!'}

**사전을 받아쓰2에 할당된 새 사전에 압축을 푼다.

우리는 또한 각 사전이 구별되는 id를 가지고 있다는 것을 확인할 수 있다.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

만약 딥 카피가 필요하다면 copy.deep copy()는 여전히 가는 길이다.

Python 2.7과 3에서 모두 받아쓰기복사본을 만드는 가장 쉽고 좋은 방법은...

단순(단일 수준) 사전의 복사본을 만드는 방법

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. python 사전의 내장 업데이트() 방법 사용

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())

물론 python >= 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참고하다

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']]

나도 처음엔 C배경 출신이라 혼란스러웠어

C에서 변수는 유형이 정의된 메모리의 위치다.변수에 할당하면 데이터가 변수의 메모리 위치에 복사된다.

그러나 Python에서는 변수가 사물에 대한 포인터에 더 가깝다.따라서 한 변수를 다른 변수에 할당하는 것이 복사되는 것이 아니라 그 변수 이름이 동일한 개체를 가리키도록 하는 겁니다.

새로 생성된 사본을 한 번에 복사하고 편집할 수 있는 방법은 다음 연락처에 문의하십시오.dict키워드 인수가 추가된 생성자:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

python의 모든 변수(stoup like)dict1또는str또는__builtins__기계 내부에 숨겨진 플라토닉 "객체"에 대한 포인터 입니다.

만약 당신이 설정한다면dict1 = dict2,당신이 가리키기만 하면 된다.dict1같은 대상(또는 메모리 위치 또는 원하는 비유)에 대해dict2. 이제 다음에 의해 참조된 개체dict1다음에 의해 참조되는 동일한 개체dict2.

확인할 수 있는 항목:dict1 is dict2그래야 한다True.또한,id(dict1)와 같아야 한다id(dict2).

너는 원한다dict1 = copy(dict2)또는dict1 = deepcopy(dict2).

과의 copy그리고deepcopy?deepcopy 의요의 할 이다.dict2(목록에서 지적하셨습니까?) 역시 사본이다.

사용하지 않는다deepcopy많이 - 필요한 코드를 쓰는 것은 대개 좋지 않은 관행이다.

dict1기본 사전 객체를 참조하는 기호.할당 중dict1dict2단지 동일한 참조를 할당한다.다음을 통해 키 값 변경dict2기호는 기본 객체를 변경하며, 이 또한 영향을 미친다.dict1헷갈리네.

참조보다 불변의 값에 대해 추론하는 것이 훨씬 쉬우므로 가능한 한 언제든지 사본을 만드십시오.

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

이것은 구문론적으로 다음과 같다.

one_year_later = dict(person, age=26)

dict2 = dict1사전을 복사하지 않는다.그것은 단지 프로그래머에게 제2의 방법을 줄 뿐이다.dict2은 같은 사전을 참조한다.

>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

Dritt 객체를 복사하는 방법은 여러 가지가 있는데, 나는 단순히

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)

다음 코드는 딥카피보다 3배 이상 빠른 json 구문을 따르는 명령어에 있다.

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)

(built-in)인(built-in)인(built-in)은 없다.dict네가 원하는 걸 하지 않아그러나 Python2(그리고 아마도 3개)에서는 쉽게 a를 만들 수 있다.ValueDict을 모방하는 계급.=원본이 변하지 않을 것을 확신할 수 있다.

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] = ..."

여기서 설명하는 lvalue 수정 패턴: Python 2.7 - lvalue 수정 구문을 참조하십시오.중요한 관찰은 다음과 같다.str그리고intPython에서 가치관처럼 행동하다 (실제로 그것들이 후드 아래 불변의 물체임에도 불구하고).그것을 관찰하는 동안, 또한 마법처럼 특별한 것은 없다는 것을 관찰하십시오.str또는int.dict매우 같은 방법으로 사용될 수 있고, 나는 많은 경우에 대해 생각할 수 있다.ValueDict일리가 있다

변수에 할당하는 클래스의 사전 속성을 복사하려고 할 때 이상한 동작이 발생함

new = copy.deepcopy(my_class.a)수정하는 것이 효과가 없다.new수정하다my_class.a

하지만 만약 그렇다면old = my_class.a그 다음에new = copy.deepcopy(old)그것은 완벽하게 작동한다. 즉, 수정한다.new영향을 미치지 않다my_class.a

왜 이런 일이 일어나는지 잘 모르겠지만, 그것이 시간을 절약하는데 도움이 되었으면 좋겠어! :)

for 루프를 사용하여 복사:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

직접 사용 가능:

dict2 = eval(repr(dict1))

여기서 객체 drcit2는 drcit1의 독립된 복사본이므로 drct1에 영향을 주지 않고 drcit2를 수정할 수 있다.

이것은 어떤 종류의 목적에도 효과가 있다.

다른 더 깨끗한 방법은 json을 사용하는 것이다.아래 규정 참조

>>> a = [{"name":"Onkar","Address": {"state":"MH","country":"India","innerAddress":{"city":"Pune"}}}]
>>> b = json.dumps(a)
>>> b = json.loads(b)
>>> id(a)
2334461105416
>>> id(b)
2334461105224
>>> a[0]["Address"]["innerAddress"]["city"]="Nagpur"
>>> a
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Nagpur'}}}]
>>> b
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Pune'}}}]
>>> id(a[0]["Address"]["innerAddress"])
2334460618376
>>> id(b[0]["Address"]["innerAddress"])
2334424569880

다른 사전을 만들려면 동일한 사전 개체에 json.dumps()와 json.loads()를 차례로 수행하십시오.당신은 별도의 받아쓰기 대상을 갖게 될 것이다.

참조URL: https://stackoverflow.com/questions/2465921/how-to-copy-a-dictionary-and-only-edit-the-copy

반응형