파이썬 문자열은 불변하지 않습니까? 그렇다면 a +“”+ b가 작동하는 이유는 무엇입니까?


109

내 이해는 Python 문자열은 변경할 수 없다는 것입니다.

다음 코드를 시도했습니다.

a = "Dog"
b = "eats"
c = "treats"

print a, b, c
# Dog eats treats

print a + " " + b + " " + c
# Dog eats treats

print a
# Dog

a = a + " " + b + " " + c
print a
# Dog eats treats
# !!!

파이썬이 할당을 막아야하지 않았습니까? 나는 아마도 뭔가를 놓치고있을 것이다.

어떤 생각?


55
문자열 자체는 변경할 수 없지만 레이블은 변경 될 수 있습니다.
mitch

6
기존 변수에 새 값을 할당하는 것은 완벽하게 유효합니다. 파이썬에는 상수가 없습니다. 이것은 데이터 유형 가변성과 무관합니다.
Felix Kling

14
id()기능을 살펴볼 수 있습니다 . a할당 전후에 다른 ID를 가지므로 다른 개체를 가리키고 있음을 나타냅니다. 마찬가지로 코드와 같이 b = a해당을 찾을 수 있습니다 a그리고 b그들은 같은 객체를 참조하고 나타내는 동일한 ID를해야합니다.
DRH


delnan의 링크는 정확히 제가 언급 한 것입니다.
mitch

답변:


180

먼저 a문자열 "Dog"를 가리 켰습니다. 그런 다음 a새 문자열 "Dog eats treats"를 가리 키 도록 변수 를 변경했습니다 . 실제로 "Dog"문자열을 변경하지 않았습니다. 문자열은 변경할 수 없으며 변수는 원하는 것을 가리킬 수 있습니다.


34
x = 'abc'와 같은 것을 시도하는 것이 훨씬 더 설득력이 있습니다. X [1] = 'X'파이썬 REPL에서
xpmatteo

1
내부를 조금 더 이해하고 싶다면 내 대답을 참조하십시오. stackoverflow.com/a/40702094/117471
Bruno Bronosky

53

문자열 객체 자체는 변경할 수 없습니다.

a문자열을 가리키는 변수 는 변경 가능합니다.

치다:

a = "Foo"
# a now points to "Foo"
b = a
# b points to the same "Foo" that a points to
a = a + a
# a points to the new string "FooFoo", but b still points to the old "Foo"

print a
print b
# Outputs:

# FooFoo
# Foo

# Observe that b hasn't changed, even though a has.

차분 a.append를 볼 (가변 임)리스트의 조작 동종 시도 @ 제이슨 A = A + "푸"내지 (3)에 상당
jimifiki

1
@jimifiki가 a.append(3) 없는 동일 a = a + 3. 짝수가 아닙니다 a += 3(내부 더하기는에 해당 .extend하지 않고에 동일 합니다 .append).

@delnan 그래서 뭐? 문자열과 목록이 다르게 작동 함을 보여주기 위해 a = a + "Foo"가 a.append (something)과 같다고 가정 할 수 있습니다. 어쨌든 그것은 동일하지 않습니다. 명백하게. a.append (something) 대신 a.extend ([something])을 읽는 것이 더 행복 했습니까? 나는이 맥락에서 큰 차이를 보지 못합니다. 그러나 아마도 나는 뭔가를 놓치고 있습니다. Thruth는 상황에 따라 달라집니다
jimifiki

@jimifiki : 그게 무슨 소리 죠? +목록과 문자열에 대해 동일하게 작동합니다. 두 피연산자를 변경하지 않고 새 복사본을 만들어 연결합니다.

6
이 모든 것을 제거 해야하는 진정으로 중요한 점은 문자열 append 은 불변이기 때문에 함수
Lily Chung

46

변수 a는 개체 "개"를 가리 킵니다. Python의 변수를 태그로 생각하는 것이 가장 좋습니다. 당신은 당신이 변화 할 때 당신이 무슨 짓을하는 다른 개체에 태그를 이동할 수 있습니다 a = "dog"a = "dog eats treats".

그러나 불변성은 태그가 아니라 객체를 의미합니다.


당신이 노력하면 a[1] = 'z'"dog""dzg", 당신은 오류를 얻을 것이다 :

TypeError: 'str' object does not support item assignment" 

문자열은 항목 할당을 지원하지 않기 때문에 변경할 수 없습니다.


19

메모리 위치 자체를 변경하지 않고 메모리 위치에있는 값을 변경할 수있는 경우에만 무언가 변경 가능합니다.

트릭은 다음과 같습니다. 변경 전후의 메모리 위치가 동일하면 변경 가능합니다.

예를 들어 목록은 변경 가능합니다. 어떻게?

>> a = ['hello']
>> id(a)
139767295067632

# Now let's modify
#1
>> a[0] = "hello new"
>> a
['hello new']
Now that we have changed "a", let's see the location of a
>> id(a)
139767295067632
so it is the same as before. So we mutated a. So list is mutable.

문자열은 변경할 수 없습니다. 어떻게 증명합니까?

> a = "hello"
> a[0]
'h'
# Now let's modify it
> a[0] = 'n'
----------------------------------------------------------------------

우리는 얻는다

TypeError : 'str'개체는 항목 할당을 지원하지 않습니다.

그래서 우리는 문자열 변형에 실패했습니다. 그것은 문자열이 불변임을 의미합니다.

재 할당 할 때 새 위치 자체를 가리 키도록 변수를 변경합니다. 여기에서는 문자열을 변경하지 않고 변수 자체를 변경했습니다. 다음은 당신이하는 일입니다.

>> a = "hello"
>> id(a)
139767308749440
>> a ="world"
>> id(a)
139767293625808

id재 할당 전후가 다르기 때문에 실제로 변이가 아니라 변수를 새 위치로 가리키고 있음을 증명합니다. 그 문자열을 변경하는 것이 아니라 해당 변수를 변경하는 것입니다.


11

변수는 객체를 가리키는 레이블 일뿐입니다. 개체는 변경할 수 없지만 원하는 경우 레이블이 완전히 다른 개체를 가리 키도록 만들 수 있습니다.


8

치다:

>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='qwer'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x109198490>

같은 값을 변수에 두 번 저장했을 때 16 진수 메모리 위치는 변경되지 않았습니다. 다른 값을 저장하면 변경되었습니다. 문자열은 변경할 수 없습니다. 열광 때문이 아니라 메모리에 새 개체를 만드는 성능 저하를 지불하기 때문입니다. 변수 a는 해당 메모리 주소를 가리키는 레이블입니다. 무엇이든 가리 키도록 변경할 수 있습니다.


7

명령문 a = a + " " + b + " " + c은 포인터를 기반으로 세분화 할 수 있습니다.

a + " "걸 줄 말한다 a변경할 수 없습니다 수있는 가리키는 및 추가 " "내 현재 작업 세트에.

기억:

working_set = "Dog "
a = "Dog" 
b = "eats"
c = "treats"

+ b걸 줄 말한다 b변경할 수 없습니다 수있는 가리키는 및 현재 작업 세트에 추가합니다.

기억:

working_set = "Dog eats"
a = "Dog" 
b = "eats"
c = "treats"

+ " " + c" "현재 세트에 추가 를 말합니다 . 그런 다음 c변경할 수없는 점을 알려주고 현재 작업 세트에 추가하십시오. 기억:

working_set = "Dog eats treats"
a = "Dog" 
b = "eats"
c = "treats"

마지막으로 a =결과 집합을 가리 키도록 포인터를 설정합니다.

기억:

a = "Dog eats treats"
b = "eats"
c = "treats"

"Dog"더 이상 포인터가 메모리 덩어리에 연결되지 않기 때문에 회수됩니다. 우리는 상주하는 메모리 섹션을 수정하지 않았습니다 "Dog". 그러나 메모리의 해당 섹션을 가리키는 레이블 (있는 경우)을 변경할 수 있습니다.


6
l = [1,2,3]
print id(l)
l.append(4)
print id(l) #object l is the same

a = "dog"
print id(a)
a = "cat"
print id(a) #object a is a new object, previous one is deleted

5

데이터와 데이터가 연결된 레이블에는 차이가 있습니다. 예를 들어 당신이 할 때

a = "dog"

데이터 "dog"가 생성되고 레이블 아래에 놓입니다 a. 레이블은 변경 될 수 있지만 메모리에있는 것은 변경되지 않습니다. 데이터 "dog"는 수행 한 후에도 여전히 메모리에 존재합니다 (가비지 수집기가 데이터를 삭제할 때까지).

a = "cat"

a이제 프로그램에서 ^가 ^을 가리 키지 "cat"만 문자열 "dog"은 변경되지 않았습니다.


3

파이썬 문자열은 변경할 수 없습니다. 그러나은 a문자열이 아닙니다. 문자열 값이있는 변수입니다. 문자열을 변경할 수는 없지만 변수의 값을 새 문자열로 변경할 수 있습니다.


2

변수는 원하는 위치를 가리킬 수 있습니다. 다음을 수행하면 오류가 발생합니다.

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE

2

파이썬 문자열 객체는 변경할 수 없습니다. 예:

>>> a = 'tanim'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281536'
>>> a = 'ahmed'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281600'

이 예제에서 우리는 다른 값을 할당해도 수정되지 않고 새로운 객체가 생성됨을 알 수 있습니다.
그리고 그것은 수정할 수 없습니다. 예:

  >>> a[0] = 'c'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    **TypeError**: 'str' object does not support item assignment

오류가 발생합니다.


2

'mutable'은 문자열의 내용을 변경할 수 있음을 의미하고 'immutable'은 추가 문자열을 추가 할 수 없음을 의미합니다.

사진 교정을 위해 클릭


1

>>> a = 'dogs'

>>> a.replace('dogs', 'dogs eat treats')

'dogs eat treats'

>>> print a

'dogs'

불변하지 않습니까?!

변수 변경 부분은 이미 논의되었습니다.


1
이것은 파이썬 문자열의 가변성을 증명하거나 반증하는 것이 아니라 replace()메서드가 새 문자열을 반환한다는 것입니다.
Brent Hronik

1

귀하의 예 에이 추가를 고려하십시오.

 a = "Dog"
 b = "eats"
 c = "treats"
 print (a,b,c)
 #Dog eats treats
 d = a + " " + b + " " + c
 print (a)
 #Dog
 print (d)
 #Dog eats treats

블로그에서 찾은보다 정확한 설명 중 하나는 다음과 같습니다.

파이썬에서는 (거의) 모든 것이 객체입니다. 우리가 일반적으로 파이썬에서 "변수"라고 부르는 것은 더 적절하게 이름이라고 불립니다. 마찬가지로 "할당"은 실제로 이름을 개체에 바인딩하는 것입니다. 각 바인딩에는 가시성을 정의하는 범위, 일반적으로 이름이 시작된 블록이 있습니다.

예 :

some_guy = 'Fred'
# ...
some_guy = 'George'

나중에 some_guy = 'George'라고 말할 때 'Fred'를 포함하는 문자열 객체는 영향을받지 않습니다. some_guy라는 이름의 바인딩을 변경했습니다. 그러나 우리는 'Fred'또는 'George'문자열 객체를 변경하지 않았습니다. 우리가 아는 한 그들은 무기한으로 살 수 있습니다.

블로그 링크 : https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/


1

위에서 언급 한 답변에 조금 더 추가하십시오.

id 재 할당시 변수 변경.

>>> a = 'initial_string'
>>> id(a)
139982120425648
>>> a = 'new_string'
>>> id(a)
139982120425776

a, 새 문자열을 가리 키도록 변수 를 변경했습니다. 이제 두 개의 string (str) 객체가 있습니다.

'initial_string'와 함께 id= 139982120425648

'new_string'와 함께 id= 139982120425776

아래 코드를 고려하십시오.

>>> b = 'intitial_string'
>>> id(b)
139982120425648

지금, b 받는 점은 'initial_string'같은이 ida재 할당하기 전에 가지고 있습니다.

따라서 'intial_string'는 돌연변이되지 않았습니다.


0

요약 :

a = 3
b = a
a = 3+2
print b
# 5

변경할 수 없음 :

a = 'OOP'
b = a
a = 'p'+a
print b
# OOP

불변 :

a = [1,2,3]
b = range(len(a))
for i in range(len(a)):
    b[i] = a[i]+1

이것은 변경 불가능하기 때문에 Python 3의 오류입니다. 그리고 분명히 불변이 아니기 때문에 파이썬 2에서는 오류가 아닙니다.


0

내장 함수 id()는 객체의 ID를 정수로 반환합니다. 이 정수는 일반적으로 메모리에서 객체의 위치에 해당합니다.

\>>a='dog'
\>>print(id(a))

139831803293008

\>>a=a+'cat'
\>>print(id(a))

139831803293120

처음에는 'a'가 139831803293008 메모리 위치에 저장됩니다. 왜냐하면 문자열 객체는 파이썬에서 변경 불가능하므로 수정하고 재 할당하려고하면 참조가 제거되고 새 메모리 위치에 대한 포인터가됩니다 (139831803293120).


0
a = 'dog'
address = id(a)
print(id(a))

a = a + 'cat'
print(id(a))      #Address changes

import ctypes
ctypes.cast(address, ctypes.py_object).value    #value at old address is intact

2
이 코드로 OP 문제를 해결할 수 있지만 코드가 OP 문제를 어떻게 해결하는지에 대한 설명을 포함하는 것이 가장 좋습니다. 이러한 방식으로 향후 방문자는 게시물에서 학습하고 자신의 코드에 적용 할 수 있습니다. SO는 코딩 서비스가 아니라 지식을위한 리소스입니다. 또한 고품질의 완전한 답변이 찬성 될 가능성이 더 높습니다. 이러한 기능은 모든 게시물이 자체 포함되어야한다는 요구 사항과 함께 포럼과 차별화되는 플랫폼으로서의 SO의 강점 중 일부입니다. 추가 정보를 추가하거나 소스 문서로 설명을 보완하기 위해 편집 할 수 있습니다
SherylHohman

-1

이 이미지가 답을 제공합니다. 읽어주세요.

여기에 이미지 설명 입력


-1

우리는 단지 두 개의 문자열 값을 연결합니다. 우리는 (a)의 값을 변경하지 않습니다. 방금 (a)는 "dogdog"값을 가진 다른 메모리 블록을 나타냅니다. 백엔드에서 하나의 변수는 동시에 두 개의 메모리 블록을 나타내지 않기 때문입니다. 연결 전의 (a) 값은 "dog"입니다. 그러나 그 후 (a)는 "dogdog"을 나타냅니다. 왜냐하면 이제 (a) 백엔드 담당자이기 때문입니다. "dogdog"값이있는 블록. 그리고 "개"는 대표입니다. by (b)와 "dog"은 (b)가 "dog"을 나타낼 때까지 쓰레기 값으로 계산되지 않습니다.

혼란은 동일한 변수 이름으로 백엔드의 메모리 블록 (데이터 또는 정보 포함)을 나타냅니다.


-2

numpy 배열을 변경 불가능하게 만들고 첫 번째 요소를 사용할 수 있습니다.

numpyarrayname[0] = "write once"

그때:

numpyarrayname.setflags(write=False)

또는

numpyarrayname.flags.writeable = False
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.