Python Language
파이썬에서 변경할 수없는 (및 Hashable) 대 가변
수색…
Mutable 대 Immutable
파이썬에는 두 가지 종류가 있습니다. 변경 불가능한 유형 및 변경 가능한 유형.
Immutables
변경할 수없는 유형의 객체는 변경할 수 없습니다. 오브젝트를 수정하려고하면 사본이 작성됩니다.
이 범주에는 정수, 수레, 복소수, 문자열, 바이트, 튜플, 범위 및 개구 수가 포함됩니다.
이 속성을 강조 표시하려면 내장 된 id
해보자. 이 함수는 매개 변수로 전달 된 객체의 고유 식별자를 반환합니다. id가 같으면 동일한 객체입니다. 변경되면 다른 객체입니다. (어떤 이들은 이것이 실제로 객체의 메모리 주소라고 말하지만, 그것들을 조심하십시오, 그들은 힘의 어두운면에서 왔습니다 ...)
>>> a = 1
>>> id(a)
140128142243264
>>> a += 2
>>> a
3
>>> id(a)
140128142243328
좋아, 1은 3이 아니야 ... 속보가 ... 아마 그렇지 않을거야. 그러나이 동작은 더 복잡한 유형, 특히 문자열의 경우에는 종종 잊혀집니다.
>>> stack = "Overflow"
>>> stack
'Overflow'
>>> id(stack)
140128123955504
>>> stack += " rocks!"
>>> stack
'Overflow rocks!'
아하! 만나다? 우리는 그것을 수정할 수 있습니다!
>>> id(stack)
140128123911472
변수 stack
의해 명명 된 문자열을 변경할 수있는 것처럼 보이지만, 실제로 수행 할 작업은 연결 결과를 포함하는 새 개체를 만드는 것입니다. 그 과정에서 낡은 물체는 아무 곳에도 나오지 않으므로 우리는 바보입니다. 다른 상황에서 그것은 더 명백했을 것입니다 :
>>> stack = "Stack"
>>> stackoverflow = stack + "Overflow"
>>> id(stack)
140128069348184
>>> id(stackoverflow)
140128123911480
이 경우 첫 번째 문자열을 유지하려면 사본이 필요하다는 것은 분명합니다. 하지만 다른 유형에 대해서는 그렇게 명백합니까?
운동
이제 불변 타입이 어떻게 작동하는지 알면, 아래 코드로 무엇을 말할 수 있을까요? 현명한가?
s = ""
for i in range(1, 1000):
s += str(i)
s += ","
돌연변이
변경 가능한 유형의 객체가 변경 될 수 있으며, 인 - 시튜 변경된다. 암시 적 복사는 수행되지 않습니다.
이 범주에는 목록, 사전, 바이어 레이 및 세트가 포함됩니다.
우리의 작은 id
함수로 계속 놀자.
>>> b = bytearray(b'Stack')
>>> b
bytearray(b'Stack')
>>> b = bytearray(b'Stack')
>>> id(b)
140128030688288
>>> b += b'Overflow'
>>> b
bytearray(b'StackOverflow')
>>> id(b)
140128030688288
(부수적으로, 필자는 ASCII 데이터가 포함 된 바이트를 사용하여 요점을 명확하게 나타내지 만 바이트는 텍스트 데이터를 보유하도록 설계되지 않았 음을 기억하십시오.
우리는 무엇을 가지고 있나? 우리는 bytearray를 만들고 수정하고 id
사용하여 수정 된 동일한 객체인지 확인할 수 있습니다. 그 사본이 아닙니다.
물론 객체가 자주 수정 될 경우 변경 가능한 유형은 변경 불가능한 유형보다 훨씬 잘 수행됩니다. 불행히도,이 재산의 현실은 종종 가장 상처를 입을 때 잊혀집니다.
>>> c = b
>>> c += b' rocks!'
>>> c
bytearray(b'StackOverflow rocks!')
괜찮아...
>>> b
bytearray(b'StackOverflow rocks!')
Waiiit a second ...
>>> id(c) == id(b)
True
과연. c
는 b
의 사본이 아닙니다. c
는 b
입니다.
운동
이제는 어떤 유형의 부작용이 가변 유형에 의해 암시되는지 더 잘 이해할 수 있습니다.이 예제에서 잘못된 점을 설명 할 수 있습니까?
>>> ll = [ [] ]*4 # Create a list of 4 lists to contain our results
>>> ll
[[], [], [], []]
>>> ll[0].append(23) # Add result 23 to first list
>>> ll
[[23], [23], [23], [23]]
>>> # Oops...
인자로 변경 가능하고 변경할 수 없다.
개발자가 mutability를 고려해야 할 주요 사용 사례 중 하나는 인수를 함수에 전달할 때입니다. 이는 해당 기능이 해당 범위에 속하지 않는 오브젝트를 수정하는 기능을 결정하거나 기능에 부작용이있는 경우이를 판별하기 때.에 매우 중요합니다. 기능 결과를 어디서 사용할 수 있는지 이해하는 것도 중요합니다.
>>> def list_add3(lin):
lin += [3]
return lin
>>> a = [1, 2, 3]
>>> b = list_add3(a)
>>> b
[1, 2, 3, 3]
>>> a
[1, 2, 3, 3]
여기서 실수는 함수에 대한 매개 변수 인 lin
로컬에서 수정할 수 있다고 생각하는 것입니다. 대신, lin
과 참조 같은 객체입니다. a
이 객체가 변경 가능하기 때문에 수정은 내부에서 수행됩니다. 즉, lin
과 a
가 모두 참조하는 객체가 수정됩니다. lin
우리가 이미의 형태로이 개체에 대한 참조가 있기 때문에 정말, 반환 할 필요가 없습니다 a
. a
및 b
끝은 동일한 객체를 참조합니다.
이것은 튜플에 대해 동일하게 적용되지 않습니다.
>>> def tuple_add3(tin):
tin += (3,)
return tin
>>> a = (1, 2, 3)
>>> b = tuple_add3(a)
>>> b
(1, 2, 3, 3)
>>> a
(1, 2, 3)
함수의 시작 부분에서, tin
및 참조 동일한 개체. a
그러나 이것은 불변 개체입니다. 그래서 함수가 그것을 수정하려 할 때, tin
수정 된 새로운 객체를받는 반면 a
a는 원래 객체에 대한 참조를 유지합니다. 이 경우 tin
반환하는 것이 필수적이거나 새 객체가 손실됩니다.
운동
>>> def yoda(prologue, sentence):
sentence.reverse()
prologue += " ".join(sentence)
return prologue
>>> focused = ["You must", "stay focused"]
>>> saying = "Yoda said: "
>>> yoda_sentence = yoda(saying, focused)
참고 : reverse
작동합니다.
이 기능에 대해 어떻게 생각하십니까? 부작용이 있습니까? 반품이 필요합니까? 전화 후, 무슨 saying
하는 가치가 있니? focused
? 동일한 매개 변수로 함수를 다시 호출하면 어떻게됩니까?