web-dev-qa-db-fra.com

Python interning chaîne

Bien que cette question n'ait aucune utilité réelle dans la pratique, je suis curieux de savoir comment Python fait l'internement de chaînes. J'ai remarqué ce qui suit.

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

C'est comme je m'y attendais.

Vous pouvez également le faire.

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

Et c'est assez intelligent!

Mais tu ne peux pas faire ça.

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

Pourquoi ne pas Python évaluer s1+"g", et réalisez que c'est la même chose que s1 et le pointer vers la même adresse? Que se passe-t-il réellement dans ce dernier bloc pour qu'il renvoie False?

77
Ze'ev G

Ceci est spécifique à l'implémentation, mais votre interprète est probablement en train d'interner des constantes au moment de la compilation mais pas les résultats d'expressions au moment de l'exécution.

Dans ce qui suit, j'utilise CPython 2.7.3.

Dans le deuxième exemple, l'expression "strin"+"g" Est évaluée au moment de la compilation et est remplacée par "string". Cela fait que les deux premiers exemples se comportent de la même manière.

Si nous examinons les bytecodes, nous verrons qu'ils sont exactement les mêmes:

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

Le troisième exemple implique une concaténation d'exécution, dont le résultat n'est pas automatiquement interné:

  # 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        

Si vous deviez manuellement intern() le résultat de la troisième expression, vous obtiendriez le même objet qu'auparavant:

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

Cas 1

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

Cas 2

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

Maintenant, votre question est de savoir pourquoi l'id est le même dans le cas 1 et pas dans le cas 2.
Dans le cas 1, vous avez affecté une chaîne littérale "123" à x et y.

Étant donné que la chaîne est immuable, il est logique que l'interpréteur ne stocke la chaîne littérale qu'une seule fois et pointe toutes les variables vers le même objet.
Par conséquent, vous voyez l'identifiant comme identique.

Dans le cas 2, vous modifiez x en utilisant la concaténation. x et y ont les mêmes valeurs, mais pas la même identité.
Les deux pointent vers des objets différents en mémoire. Ils ont donc des opérateurs id et is différents renvoyés False

0
cppcoder