불변 대 변이 유형


186

불변 유형이 무엇인지 혼란 스럽습니다. 필자의 float책에서 이러한 유형의 예제를 사용 하면 객체가 변경 불가능한 것으로 간주됩니다.

class RoundFloat(float):
    def __new__(cls, val):
        return float.__new__(cls, round(val, 2))

이것은 클래스 구조 / 계층 때문에 불변으로 간주됩니까?, 의미 float는 클래스의 최상위에 있으며 자체 메서드 호출입니다. 이 유형의 예제와 비슷합니다 (내 책 dict이 변경 가능 하다고 말하더라도 ).

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

변경 가능한 것은 클래스 내부에 메소드가 있지만이 유형의 예제는 다음과 같습니다.

class SortedKeyDict_a(dict):
    def example(self):
        return self.keys()

또한 마지막 class(SortedKeyDict_a)유형에 대해이 유형의 세트를 전달하면 :

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

example메소드 를 호출하지 않고 사전을 리턴합니다. SortedKeyDict__new__오류로 플래그를. RoundFloat클래스에 정수를 전달하려고 시도했지만 __new__오류가 표시되지 않았습니다.


[.]python을 사용 하여 List 할당을 확인 하여 copy.copy를 사용할 때 변경 가능성에 대한 자세한 정보를 확인할 수도 있습니다.
agf

답변:


232

뭐? 플로트는 불변입니까? 하지만 난 못해

x = 5.0
x += 7.0
print x # 12.0

"mut"x 아닌가?

글쎄, 문자열이 변경 불가능하다는 데 동의합니까? 그러나 같은 일을 할 수 있습니다.

s = 'foo'
s += 'bar'
print s # foobar

변수의 값은 변하지 만 변수가 참조하는 것을 변경하면 변합니다. 변경 가능한 유형은 이러한 방식으로 변경 될 수 있으며 "제자리에서"변경 될 수도 있습니다.

차이점이 있습니다.

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

구체적인 예

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]

5
당신이 설명하는 것은 나에게 의미합니다 : 가변 변수는 참조로 전달되고 불변 변수는 값으로 전달됩니다. 이 올바른지 ?
Lorenz Meyer

17
거의 아니지만 정확히는 아닙니다. 기술적으로 모든 변수는 파이썬에서 참조로 전달되지만 C에서는 값으로 전달하는 것과 같은 의미가 def f(my_list): my_list = [1, 2, 3]있습니다. C에서 참조로 전달하면 인수의 값이 해당 함수를 호출하여 변경 될 수 있습니다. 파이썬에서, 그 함수는 아무것도하지 않습니다. def f(my_list): my_list[:] = [1, 2, 3]뭔가를 할 것입니다.
morningstar

6
가변 유형은 제자리에서 변경할 수 있습니다. 불변 유형은 제자리에서 변경할 수 없습니다. 그것이 파이썬이 세상을 보는 방식입니다. 변수가 함수에 전달되는 방식과 관계가 없습니다.
ychaouche

13
파이썬 시맨틱과 C ++ 패스 바이 레퍼런스 시맨틱의 주요 차이점은 할당은 파이썬에서 돌연변이가 아니라 C ++에 있다는 것입니다. (그러나 물론 같은 할당을 증강한다는 사실에 의해 복잡 그 a += b때때로 이다 , 돌연변이. 그리고 사실은 더 큰 객체의 일부에 할당 가끔 큰 개체의 돌연변이, 부분 - 예를 들어 단지 결코 돌연변이를 의미 a[0] = b하는 mutate하지 않습니다 a[0], 그러나 아마도 돌연변이 a가 될 것입니다 ... 그렇기 때문에 C ++의 관점에서 물건을 넣지 않고 파이썬 자체의 용어로 설명하는 것이 좋습니다 ...)
abarnert

2
불변의 의미를 이해하는 데 필수적인 id ()를 사용하지 않기 때문에이 답변이 잘못되었습니다.
pawel_winzig

185

파이썬은 모든 데이터를 객체로 나타냅니다. 목록 및 사전과 같은 일부 개체는 변경 가능하므로 ID를 변경하지 않고 내용을 변경할 수 있습니다. 정수, 부동 수, 문자열 및 튜플과 같은 다른 객체는 변경할 수없는 객체입니다. 이해하기 쉬운 방법은 객체 ID를 살펴 보는 것입니다.

아래에는 불변의 문자열이 있습니다. 내용을 변경할 수 없습니다. 그것은을 올릴 것이다 TypeError당신이 그것을 변경하려고합니다. 또한 새 컨텐츠를 할당하면 컨텐츠를 수정하는 대신 새 오브젝트가 작성됩니다.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

목록으로 그렇게 할 수 있으며 객체의 정체성을 바꾸지 않습니다.

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

Python의 데이터 모델에 대한 자세한 내용을 보려면 Python 언어 참조를 살펴보십시오.


4
+1 파이썬 문서에 대한 링크. 그러나 오늘 파이썬 2 & 3을 차별화해야한다는 것을 깨달을 때까지 약간의 시간이 걸렸습니다.
benjamin

107

일반적인 불변 유형 :

  1. 번호 : int(), float(),complex()
  2. 불변 서열 : str(), tuple(), frozenset(),bytes()

일반적인 가변 유형 (거의 모든 것) :

  1. 가변 시퀀스 : list(),bytearray()
  2. 세트 유형 : set()
  3. 매핑 유형 : dict()
  4. 클래스, 클래스 인스턴스
  5. 기타

유형이 변경 가능한지 여부를 신속하게 테스트하는 한 가지 방법은 id() 내장 기능 하는 것입니다.

정수를 사용하는 예,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

목록을 사용하여

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)

11
잘 설명했다. 의 확인 개념을 좋아했습니다 id(). +1.
Parag Tyagi

4
실제로 사용은 id()여기에서 오도됩니다. 주어진 객체는 수명 동안 항상 동일한 ID를 갖지만, 다른 시간에 존재하는 다른 객체는 가비지 수집으로 인해 동일한 ID를 가질 수 있습니다.
augurar

37

우선, 클래스에 메소드가 있는지 또는 클래스 구조가 변경되는지 여부는 변경 가능성과 관련이 없습니다.

ints 및 floats는 변경할 수 없습니다 . 만약 내가한다면

a = 1
a += 5

이름 a1첫 번째 행의 메모리 어딘가에 . 두 번째 줄에, 그를 조회 1, 추가 5취득, 6다음 점을 a그에서 6메모리에 - 그것은하지 않았다 변경1 A와를 6어떤 식 으로든. 다른 변경 불가능한 유형을 사용하여 다음 예제에 동일한 논리가 적용됩니다 .

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

내용은 변경 가능한 유형, 나는 actallly 일 할 수있는 이 메모리에 저장된 값을 변경을 . 와:

d = [1, 2, 3]

나는의 위치 목록을 만들었습니다 1, 2그리고 3메모리를. 내가한다면

e = d

난 그냥 포인트 e받는 동일한list d 에서 포인트. 그런 다음 할 수 있습니다 :

e += [4, 5]

그리고 지점 ed지점이 업데이트되어 목록이 45 메모리를.

불변 유형 으로 돌아가서 tuple다음 과 같이하면 :

f = (1, 2, 3)
g = f
g += (4, 5)

그때 f 여전히 원본tuple 만 가리 킵니다 g. 완전히 새로운 것을 가리 켰 습니다.tuple . .

이제, 당신의 예를 들어

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

당신이 통과하는 곳

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(A 인 tupletuples등) val때문에, 오류를 받고있어 tuple의가없는 .clear()방법을 - 당신이 통과해야 할 것 dict(d)같은 val일에 대한 당신이 빈 얻을 것이다 경우에, SortedKeyDict결과를.


2
이것은 매우 좋은 설명입니다. 이 질문과 그것을 설명하기 위해 많은 흥미로운 (새로운) 관점을 좋아했습니다.
실패한 과학자

25

다른 언어 (루비와 같이 파이썬과 비슷한 언어는 제외)에서 파이썬으로오고 다른 언어로 이해하려고하면 사람들이 혼란스러워하는 부분은 다음과 같습니다.

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

파이썬에서 할당은 파이썬에서 돌연변이가 아닙니다.

C ++ 에서을 쓰면을 a = 2호출 a.operator=(2)하여에 저장된 객체를 변경합니다 a. (그리고 저장된 물건 없다면a 오류입니다.)

파이썬에서는 a = 2저장된 모든 것에 아무 것도하지 않습니다 a. 그것은 단지 2지금 a대신에 저장 된다는 것을 의미합니다 . (에 저장된 객체 없으면 a괜찮습니다.)


궁극적으로 이것은 더 깊은 구별의 일부입니다.

C ++와 같은 언어의 변수는 메모리의 형식화 된 위치입니다. 경우 a입니다 int, 그 수단은 컴파일러가 해석하도록되어 알고있는 4 바이트 곳입니다 int. 따라서 그렇게하면 a = 24 바이트의 메모리에 저장된 내용을 0, 0, 0, 1에서0, 0, 0, 2 . 다른 곳에서 다른 int 변수가 있으면 자체 4 바이트가 있습니다.

파이썬과 같은 언어의 변수는 생명력이있는 객체의 이름입니다. 숫자에 대한 객체 1와 숫자 에 대한 다른 객체가 2있습니다. 그리고 a로 표현되는 4 바이트의 메모리가 int아니라 1객체 를 가리키는 이름 일뿐 입니다. a = 2숫자 1을 숫자 2로 바꾸는 것은 이치에 맞지 않습니다 (파이썬 프로그래머에게 우주의 기본 작업을 변화 시키기에는 너무 많은 힘을 줄 것입니다). 대신 객체를 a잊어 버리고 1객체를 가리 키십시오 2.


할당이 돌연변이가 아닌 경우에 따라서, 무엇 이다 돌연변이는?

  • 같은 돌연변이 문서화하는 방법을 호출 a.append(b). (이러한 메소드는 거의 항상을 반환 None합니다.) 불변 유형에는 그러한 메소드가 없으며 일반적으로 변경 가능한 유형이 있습니다.
  • a.spam = b또는 과 같이 객체의 일부에 할당 a[0] = b. 불변 유형은 속성 또는 요소에 대한 할당을 허용하지 않으며, 가변 유형은 일반적으로 둘 중 하나를 허용합니다.
  • 때로는과 같이 확장 된 할당을 사용하는 a += b경우가 종종 있습니다. 가변 유형은 일반적으로 값을 변경합니다. 불변 유형은 절대로하지 않고 대신 사본을 제공합니다 (계산 a + b후 결과를에 할당 a).

그러나 할당이 돌연변이가 아닌 경우 객체 돌연변이의 일부에 할당하는 방법은 무엇입니까? 그것이 까다로워지는 곳입니다. a[0] = b하지 아니 하는 mutate a[0](다시, C는 달리 ++),하지만 하지 의 mutate를a 간접적으로 제외하고 C ++과 달리 .

이 모든 것은 아마 더 나은 이유가 없습니다 당신이 사용하는 언어의 관점에서 파이썬의 의미를 넣어 시도하고 대신 자신의 조건에 파이썬의 의미를 배울 수 있습니다.


2
a = 'hi'라고 말하십시오. a [0] = 'f'는 'print a'를 출력합니다 'fi'(지금까지 내가 있습니까?) ? a [n]도 지금 자신의 자리를 가지고 있고 그 가치를 바꾸는 것이 다른 가치를 가리키는가?
Daniel Springer

19

객체가 변경 가능한지 여부는 유형에 따라 다릅니다. 이것은 특정 메소드가 있는지 여부 또는 클래스 계층 구조에 의존하지 않습니다.

사용자 정의 형식 (예 : 클래스)은 일반적으로 변경 가능합니다. 불변 유형의 단순한 서브 클래스와 같은 예외가 있습니다. 다른 불변의 유형에는 몇 가지 기본 유형과 같은 int, float, tuplestr 뿐만 아니라 일부 파이썬 클래스 C로 구현 된,

"Python Language Reference"의 "Data Model"장에 대한 일반적인 설명 :

일부 개체의 값은 변경 될 수 있습니다. 값을 변경할 수있는 객체는 변경 가능하다고합니다. 일단 생성 된 값을 변경할 수없는 객체를 불변이라고합니다.

(변경 가능한 객체에 대한 참조가 포함 된 변경 불가능한 컨테이너 객체의 값은 후자의 값이 변경 될 때 변경 될 수 있지만, 포함 된 객체의 컬렉션을 변경할 수 없기 때문에 컨테이너는 여전히 불변으로 간주됩니다. 따라서 불변성은 엄격하지 않습니다. 변경 불가능한 값을 갖는 것과 동일하게 더 미묘합니다.)

객체의 가변성은 유형에 따라 결정됩니다. 예를 들어 숫자, 문자열 및 튜플은 변경할 수 없지만 사전과 목록은 변경할 수 있습니다.


+1 일부 확장 유형 (그 정의를 검토하고 싶을 수도 있지만 Python의 모든 내장 유형은 C로 구현 됨)은 변경할 수 없습니다. 다른 사람들 (대부분 말하면 감히 말할 것입니다)은 완벽하게 변경 가능합니다.

@delnan "확장 유형"은 무엇입니까?
eyquem

@eyquem : 내 대답에 "확장 유형"이라는 용어를 잘못 사용했으며 delnan은 그것을 언급했습니다. 그의 의견 후 나는 내 대답을 수정 하고이 용어를 사용하지 않았습니다.
taleinat

19

가변 객체와 불변 객체의 차이점

정의

가변 객체 : 생성 후 변경할 수있는 객체입니다.
불변 객체 : 생성 후 변경할 수없는 객체입니다.

파이썬에서는 불변 객체의 값을 변경하면 새로운 객체가 생성됩니다.

가변 객체

다음은 파이썬에서 변경 가능한 유형의 객체입니다.

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

불변 개체

다음은 불변 유형의 Python 객체입니다.

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

답변되지 않은 질문

질문 : 문자열은 불변 유형입니까?
: , 그러나 당신은 이것을 설명 할 수 있습니다 : 증명 1 :

a = "Hello"
a +=" World"
print a

산출

"Hello World"

위 예제에서 문자열은 "Hello"로 생성 된 후 "Hello World"로 변경되었습니다. 이는 문자열이 변경 가능한 유형임을 의미합니다. 그러나 변경 가능한 유형인지 여부를 확인하기 위해 ID를 확인할 때가 아닙니다.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

산출

String is Immutable

증명 2 :

a = "Hello World"
a[0] = "M"

산출

TypeError 'str' object does not support item assignment

질문 : Tuple은 불변 타입입니까?
: , 그렇습니다 . 증명 1 :

tuple_a = (1,)
tuple_a[0] = (2,)
print a

산출

'tuple' object does not support item assignment

[46]에서 : a = "Hello"[47]에서 : id (a) Out [47] : 140071263880128 [48]에서 : a = a.replace ( "H", "g") [49]에서 : a Out [49] : 'gello'In [50] : id (a) Out [50] : 140071263881040
Argus Malware

위의 예에서 아이템 할당 문제를 증명할 수 있습니까?
Argus Malware

불변 유형에서는 항목 할당이 문제가되지 않습니다. 귀하의 경우 문자열 a를 변경하지만 메모리에서 새 변수에 할당합니다. 내 경우의 항목 할당은 목록이나 사전의 경우와 같이 변수의 메모리를 변경하지 않습니다. 당신이하고있는 경우 기존 변수를 수정 새 변수를하지 만드는 교체
아난드 tripathi

귀하의 경우 @ArgusMalware, 두 번째 ID는 GC에 의해 재활용 된 첫 번째 ID 때문에 동일하므로 두 번째 ID는 메모리를 재사용합니다.
Cologler

11

가변 객체는 적어도 객체를 돌연변이시킬 수있는 방법을 가져야합니다. 예를 들어, list객체에는 append실제로 객체를 변경하는 메소드가 있습니다.

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

그러나 클래스 float에는 float 객체를 변경하는 메소드가 없습니다. 넌 할 수있어:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

그러나 =피연산자는 방법이 아닙니다. 변수와 오른쪽에있는 것 사이에 바인드를 만듭니다. 절대 개체를 변경하거나 만들지 않습니다. 그것은 지금부터 변수가 무엇을 가리킬 것인지에 대한 선언입니다.

당신이 할 때 피연산자의 테 결과로 생성되는 느릅 나무 새로운 플로트에 변수를 바인드합니다 .b = b + 0.1=5 + 0.1

변수를 기존 객체에 변경 가능 여부를 지정하면 =피연산자가 변수를 해당 객체에 바인딩합니다. 그리고 더 이상 아무 일도 일어나지 않습니다

어느 쪽이든, =그냥 바인딩합니다. 개체를 변경하거나 만들지 않습니다.

당신이 할 때 a = 1.0, =피연산자는 float를 만들지 않고 1.0선의 일부를 만듭니다 . 실제로 작성할 때 float 객체를 반환하는 생성자 호출 1.0의 약어입니다 float(1.0). (따라서 입력 1.0하고 Enter 키를 누르면 "에코" 가 표시되는 이유입니다.1.0 아래에 인쇄됩니다. 이것이 호출 한 생성자 함수의 반환 값입니다)

지금, 만약 b부동이고 당신 할당 a = b, 두 변수가 같은 객체를 가리키는되지만, 수 comunicate 수 없습니다의 차이와 자체 개체가 inmutable이며, 때문에 당신이 할 경우 실제로 변수 b += 1, 이제 b새로운 개체를 가리킨 a것입니다 여전히 옛 사람을 b가리키며 무엇 을 가리키고 있는지 알 수 없습니다 .

하지만 만약 c입니다,의이 말을하자 list, 당신 지정할 a = c지금 a하고 c있습니다 "comunicate 수"있기 때문에 list변경할 수 있으며, 당신이 경우에 c.append('msg'), 그럼 그냥 확인a 하면 메시지가 표시됩니다.

(그러면 모든 객체에는 고유 한 ID 번호가 있습니다.으로 얻을 수 있습니다 id(x). 따라서 객체가 동일한 지 또는 고유 한 ID가 변경되었는지 여부를 확인할 수 있습니다.)


6

인스턴스화시 SUBSEQUENTLY 로 변경할 수없는 해당 클래스의 각 객체에 고정 된 값이있는 경우 클래스는 변경할 수 없습니다.

다시 말해, 해당 변수의 전체 값을 변경 (name)하거나 그대로 두십시오.

예:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

이것이 작동하고 hello world를 인쇄 할 것으로 예상 했지만 다음과 같은 오류가 발생합니다.

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

인터프리터가 말합니다 : 나는이 문자열의 첫 번째 문자를 변경할 수 없습니다

string작동하게 하려면 전체를 변경 해야합니다.

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

이 표를 확인하십시오.

여기에 이미지 설명을 입력하십시오

출처


파이썬 문자열의 구성 요소를 위에서보다 간결하게 수정하는 방법은 무엇입니까?
Luke Davis

@LukeDavis 할 수 my_string = 'h' + my_string[1:]있습니다. 그러면 my_string이라는 새 문자열이 생성되고 원래 my_string이 사라집니다 ( id(my_string)이것을 보려면 인쇄 하십시오). 물론 그것은 매우 유연하지 않습니다.보다 일반적인 경우에 당신은리스트로 l = list(my_string) l[0] = 'h' my_string = ''.join(l)
바꾸고

5

가변 / 불변이 실제로 무엇을 의미하는지에 대해 당신이 싸우고있는 것 같습니다 . 여기 간단한 설명이 있습니다 :

먼저 우리는 설명을 기반으로하는 기초가 필요합니다.

따라서 가상 객체로 프로그래밍하는 것, 컴퓨터 메모리에 일련의 이진수로 저장된 것을 생각하십시오. (그러나 이것을 너무 열심히 상상하지 마십시오. ^^) 이제 대부분의 컴퓨터 언어에서이 이진수로 직접 작업하지 않고 이진 숫자의 해석을 사용합니다.

예를 들어 0x110, 0xaf0278297319 또는 이와 유사한 숫자는 생각하지 않지만 6과 같은 숫자 또는 "Hello, world"와 같은 문자열에 대해서는 생각합니다. 이 적은 숫자 나 문자열이 컴퓨터 메모리의 이진수를 해석하는 것은 아닙니다. 변수 값에 대해서도 마찬가지입니다.

한마디로 : 우리는 하지 않습니다 와 프로그램 의 실제 값 만에 실제 이진 값의 해석.

이제 우리는 논리와 다른 "가장 깔끔한 것"을 위해 변경되어서는 안되는 해석을 가지고 있지만 변경 될 수있는 해석이 있습니다. 예를 들어 도시의 시뮬레이션, 즉 가상 객체가 많고 그 중 일부가 주택 인 프로그램을 생각해보십시오. 이제 이러한 가상 객체 (주택)를 변경해도 여전히 동일한 주택으로 간주 될 수 있습니까? 물론 그들은 할 수 있습니다. 따라서 그것들은 변할 수있다 : "완전히"다른 객체가되지 않고 변경 될 수있다.

이제 정수를 생각해보십시오. 이것들은 가상 객체이기도합니다 (컴퓨터 메모리의 이진수 순서). 따라서 값을 6 씩 증가시키는 것과 같이 그 중 하나를 변경해도 여전히 6입니까? 물론 아닙니다. 따라서 모든 정수는 불변입니다.

따라서 가상 객체가 변경되면 실제로 다른 가상 객체가된다는 것을 불변이라고합니다.

최종 비고 :

(1) 실제 언어 경험과 불변 경험을 특정 언어의 프로그래밍과 섞지 마십시오.

모든 프로그래밍 언어에는 어떤 객체가 뮤트 될 수 있고 어떤 객체가 뮤팅되지 않을 것인지에 대한 자체 정의가 있습니다.

따라서 의미의 차이를 이해할 수는 있지만 여전히 각 프로그래밍 언어에 대한 실제 구현을 배워야합니다. ... 실제로 6이 7이되기 위해 음소거 될 수있는 언어의 목적이있을 수 있습니다. 그리고 다시 이것은 평행 우주의 시뮬레이션과 같이 아주 미친 것이나 흥미로운 것입니다. ^^

(2)이 설명은 확실히 과학적인 것이 아니며, 변경 가능과 불변의 차이를 파악하는 데 도움이됩니다.


5

이 답변의 목표는 돌연변이 / 비 돌연변이 (불변 / 불변)를 다루고 있는지, 가능한 경우 어떻게해야하는지에 대한 모든 좋은 아이디어를 찾을 수있는 단일 장소를 만드는 것입니다. 돌연변이가 바람직하지 않은 경우가 있으며, 이와 관련하여 파이썬의 행동은 다른 언어에서 들어오는 코더에 반 직관적이라고 느낄 수 있습니다.

@ mina-gabriel의 유용한 게시물에 따르면 :

위의 내용을 분석하고 @ arrakëën의 게시물을 결합합니다.

예기치 않게 변경할 수없는 것은 무엇입니까?

  • 스칼라 (단일 값을 저장하는 변수 유형)가 예기치 않게 변경되지 않습니다
    • 숫자 예 : int (), float (), complex ()
  • 몇 가지 "변경 가능한 시퀀스"가 있습니다 :
    • str (), 튜플 (), frozenset (), 바이트 ()

무엇을 할 수 있습니까?

  • 객체와 같은 목록 (목록, 사전, 세트, ​​bytearray ())
  • 여기에 게시물은 클래스와 클래스 인스턴스를 말하지만 클래스가 상속하는 내용 및 / 또는 빌드 방법에 따라 달라질 수 있습니다.

"예기치 않게"는 다른 언어의 프로그래머가이 동작을 기대하지 않을 수 있음을 의미합니다 (예외 또는 Ruby 및 다른 "Python like"언어).

이 토론에 추가 :

이 동작은 메모리를 사용하는 큰 데이터 구조의 여러 복사본으로 실수로 코드를 채우는 것을 방지 할 때 유리합니다. 그러나 이것이 바람직하지 않은 경우 어떻게 해결할 수 있습니까?

목록을 사용하면 간단한 해결책은 다음과 같이 새로운 것을 만드는 것입니다.

list2 = 목록 (list1)

다른 구조를 사용하면 솔루션이 까다로울 수 있습니다. 한 가지 방법은 요소를 반복하여 비어있는 새 데이터 구조 (같은 유형)에 추가하는 것입니다.

함수는 변경 가능한 구조를 전달할 때 원본을 변경할 수 있습니다. 말하는 방법?

  • 이 글타래에 대한 다른 코멘트에 대한 테스트가 있지만 이러한 테스트가 완전한 증거가 아님을 나타내는 코멘트가 있습니다
  • object.function ()은 원래 객체의 메소드이지만 일부 돌연변이입니다. 아무 것도 돌려주지 않으면 아마 할 것입니다. .append ()는 이름을 지정하지 않고 테스트하지 않고 변경 될 것으로 예상합니다. .union ()은 set1.union (set2)의 합집합을 반환하며 변경하지 않습니다. 확실하지 않은 경우, 함수는 리턴 값을 점검 할 수 있습니다. return = None이면 변경되지 않습니다.
  • 경우에 따라 sorted ()가 해결 방법이 될 수 있습니다. 정렬 된 버전의 원본을 반환하기 때문에 다른 방식으로 원본 작업을 시작하기 전에 변경되지 않은 복사본을 저장할 수 있습니다. 그러나이 옵션은 원본 요소의 순서에 신경 쓰지 않는다고 가정합니다 (그렇게하면 다른 방법을 찾아야 함). 대조적으로 .sort ()는 원본을 변경합니다 (예상대로).

비표준 접근 방식 (유용한 경우) : MIT 라이센스로 게시 된 github에서 다음을 발견했습니다.

  • github 저장소 아래 : tobgu 이름 : pyrsistent
  • 의미 : 돌연변이가 바람직하지 않은 경우 핵심 데이터 구조 대신 사용되도록 작성된 Python 영구 데이터 구조 코드

사용자 정의 클래스의 경우 @semicolon은 __hash__변경 가능한 객체에 일반적으로 __hash__()함수 가 없어야하기 때문에 함수 가 있는지 확인하는 것이 좋습니다 .

이것이 내가 지금이 주제에 대해 모은 전부입니다. 다른 아이디어, 수정 등도 환영합니다. 감사.


3

차이점을 생각하는 한 가지 방법 :

파이썬에서 불변 객체에 대한 할당은 깊은 사본으로 생각할 수 있지만 가변 객체에 대한 할당은 얕습니다.


1
이것은 올바르지 않습니다. 파이썬의 모든 과제는 참조입니다. 복사가 필요하지 않습니다.
augurar

3

가장 간단한 답변 :

변경 가능한 변수는 값이 변경 될 수있는 반면 변경 불가능한 변수의 값은 변경되지 않습니다. 불변 변수를 수정하면 동일한 변수가 다시 작성됩니다.

예:

>>>x = 5

x가 참조하는 값 5를 만듭니다.

x-> 5

>>>y = x

이 문장은 y가 x의 5를 가리 키도록합니다.

x -------------> 5 <----------- y

>>>x = x + y

x는 정수 (불 변형)이므로 재 구축되었습니다.

명령문에서 RHS의 표현식은 값 10이되며 이것이 LHS (x)에 지정되면 x는 10으로 다시 빌드됩니다.

x ---------> 10

y ---------> 5


-1

모든 답변을 읽지는 못했지만 선택한 답변이 정확하지 않으며 저자는 변수를 다시 할당 할 수 있다는 것은 모든 데이터 유형이 변경 가능하다는 것을 의미한다고 생각합니다. 그렇지 않습니다. 변경 가능성은 가치를 전달하는 것이 아니라 참조를 통한 전달과 관련이 있습니다.

당신이 목록을 만들었다 고 말할 수 있습니다

a = [1,2]

말을한다면 :

b = a
b[1] = 3

B에 값을 다시 할당하더라도 a에 값을 다시 할당합니다. "b = a"를 할당 할 때 발생합니다. 값의 사본이 아닌 "참조"를 오브젝트에 전달합니다. 이것은 문자열, 부동 소수점 등의 경우에는 해당되지 않습니다. 이렇게하면 목록, 사전 및 좋아요를 변경할 수 있지만 부울, 부동 등은 변경할 수 없습니다.


-1

불변 개체의 경우 할당은 예를 들어 새로운 값의 사본을 만듭니다.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

변경 가능한 객체의 경우 할당시 다른 값의 사본이 생성되지 않습니다. 예를 들어

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list

1
절대적으로 맞지 않습니다. 할당 은 복사본을 만들지 않습니다 . nedbatchelder.com/text/names.html을 읽어 보십시오 . 첫 번째 경우 x=10에는 단순히 또 다른 할당 이며 x[2] = 5mutator 메소드 를 호출합니다. int객체에는 단순히 mutator 메소드 가 없지만 파이썬 할당의 의미 는 유형에 의존하지 않습니다
juanpa.arrivillaga

-2

파이썬에는 쉽게 알 수있는 방법이 있습니다.

불변 :

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

변하기 쉬운:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

과:

>>> s=abs
>>> s is abs
True

그래서 내장 함수도 파이썬에서 변경할 수 없다고 생각합니다.

그러나 float가 어떻게 작동하는지 이해하지 못합니다.

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

너무 이상하다.


그러나 그것은 분명히 유효하지 않습니다. 튜플은 불변이기 때문에. 를 입력 x = (1, 2)한 다음 변경하고 시도 x하면 불가능합니다. 변경 가능성을 확인하는 한 가지 방법 hash은 내장 객체에 대해 작동하는 것입니다. hash(1) hash('a') hash((1, 2)) hash(True)모든 것이 작동하고 hash([]) hash({}) hash({1, 2})모든 것이 작동하지 않습니다.
세미콜론

@semicolon 사용자 정의 클래스는 일반적으로 사용자 정의 클래스가 변경 가능하더라도 hash()객체가 __hash__()메소드를 정의하면 작동합니다 .
augurar

1
@augurar 그렇습니다.하지만 파이썬에는 실제 정적 타이핑이나 공식적인 보증이 없기 때문에 파이썬에서 아무것도 보장하지 않습니다. 그러나 hash변경 가능한 객체는 일반적으로 __hash__()메소드를 가져서는 안되기 때문에 메소드는 여전히 좋은 방법입니다. 사전에서 키를 만드는 것은 위험하기 때문입니다.
세미콜론

1
@augurar 및 세미콜론 (또는 다른 사람들이 알고 있다면) : __hash __ () 솔루션 ... 사용자 정의 클래스의 작성자가 그것을 추가해야합니까? 그렇다면 규칙은 존재하는 경우 개체를 변경할 수없는 것입니다. 존재하지 않는 경우 제작자가 꺼져 있으면 단순히 떠날 수 있으므로 알 수 없습니다.
TMWP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.