2013-03-21 3 views
54

이 질문은 실제로 사용하지는 않지만 파이썬이 어떻게 인턴 문자열을 작성하는지 궁금합니다. 나는 다음을 주목했다.파이썬 문자열 interning

>> "string" is "string" 
>> True 

이것은 예상대로입니다.

이 작업을 수행 할 수도 있습니다.

>> "strin"+"g" is "string" 
>> True 

그리고 그것은 꽤 영리합니다!

하지만이를 수행 할 수 없습니다.

>> s1 = "strin" 
>> s2 = "string" 
>> s1+"g" is s2 
>> False 

왜 파이썬은 s1+"g"을 평가, 그것은 s1과 동일 실현과 같은 주소를 가리하지 않을까요? 마지막 블록에서 실제로 어떤 일이 일어나서 False을 반환합니까?

답변

60

이것은 구현에 따라 다르지만 인터프리터는 아마도 런타임시의 결과가 아닌 컴파일 타임 상수 일 수 있습니다.

다음은 CPython 2.7.3을 사용합니다.

두 번째 예에서는 "strin"+"g"이라는 표현식을 컴파일 할 때 계산되며 "string"으로 바뀝니다. 이것은 처음 두 예제가 똑같이 동작하도록합니다. 우리가 바이트 코드를 살펴보면

, 우리는 그들이 정확히 같은 것을 볼 수 있습니다 :

:

# s1 = "string" 
    2   0 LOAD_CONST    1 ('string') 
       3 STORE_FAST    0 (s1) 

    # s2 = "strin" + "g" 
    3   6 LOAD_CONST    4 ('string') 
       9 STORE_FAST    1 (s2) 

세 번째 예는 자동으로 구금되지 않는 결과가있는 런타임 연결을 포함한다 당신이 있다면

# s3a = "strin" 
    # s3 = s3a + "g" 
    4   12 LOAD_CONST    2 ('strin') 
      15 STORE_FAST    2 (s3a) 

    5   18 LOAD_FAST    2 (s3a) 
      21 LOAD_CONST    3 ('g') 
      24 BINARY_ADD   
      25 STORE_FAST    3 (s3) 
      28 LOAD_CONST    0 (None) 
      31 RETURN_VALUE   

수동으로 세 번째 식의 결과를 intern()하려면 이전과 동일한 개체를 얻을 것 :

>>> s3a = "strin" 
>>> s3 = s3a + "g" 
>>> s3 is "string" 
False 
>>> intern(s3) is "string" 
True 
+13

어떻게 섹시한 출력을 얻었습니까? – Serdalis

+13

@Serdalis : http://docs.python.org/2/library/dis.html – NPE

+12

그리고 기록을 위해 : 파이썬의 peep-hole 최적화는 상수에 대한 산술 연산을 미리 계산합니다 (''string1 "+"s2 "' , '10 + 3 * 20' 등)을 컴파일 타임에 제한하지만 결과는 * 시퀀스 *를 단지 20 개의 요소로 제한합니다 (바이트 코드를 과도하게 확장하지 못하도록 [없음] * 10 ** 1000을 방지). ''strin "+"g "'를''string ''에 접목시킨 것은이 최적화입니다. 결과는 20 자보다 짧습니다. –

0

사례 1

>>> x = "123" 
>>> y = "123" 
>>> x == y 
True 
>>> x is y 
True 
>>> id(x) 
50986112 
>>> id(y) 
50986112 

사례 2

>>> x = "12" 
>>> y = "123" 
>>> x = x + "3" 
>>> x is y 
False 
>>> x == y 
True 

ID가 케이스 (1) 동일이 아닌 경우 1 년의 경우 2
에 왜 지금, 당신의 질문은, 문자 리터럴 "123"xy에 할당했습니다.

문자열이 불변이므로 인터프리터가 문자열 리터럴을 한 번만 저장하고 모든 변수를 동일한 객체로 지정하는 것이 좋습니다.
따라서 ID는 동일합니다.

경우 2에서는 연결을 사용하여 x을 수정합니다. xy은 모두 동일한 값이지만 동일한 ID는 아닙니다.
둘 다 메모리의 다른 개체를 가리 킵니다.따라서 그들은 다른 idis 연산자를 반환했습니다 False

+0

어쨌든, 문자열이 불변이므로, x + "3"을 할당하고 (문자열을 저장하기위한 새로운 지점을 찾고) y와 같은 참조를 할당하지 않습니까? – Andrea

+0

그 때문에 새로운 문자열을 기존의 모든 문자열과 비교해야하기 때문에; 잠재적으로 매우 비싼 조작. 예를 들어, 메모리를 줄이기 위해 할당 한 후에 백그라운드에서이 작업을 수행 할 수 있지만 문자열이 프로세스에서 이동 되었기 때문에 (예 : id (x)! = id (x)) 평가. – DylanYoung

+0

@AndreaConte 문자열의 연결은 새 문자열을 생성 할 때마다 사용 된 모든 문자열 풀을 조회하는 추가 작업을 수행하지 않기 때문에 발생합니다. 반면에 인터프리터는 x = "12"+ "3"'x = "123"'(하나의 표현식에서 두 문자열 리터럴의 연결) 표현식을 "최적화"하여 할당이 실제로 조회를 수행하고 'y = "123"'과 같은 "내부"문자열. – derenio