2010-11-12 18 views
8

Ceci est pour Python 2.6.Est-ce un bug? Les variables sont des références identiques à la même chaîne dans cet exemple (Python)

Je ne pouvais pas comprendre pourquoi et b sont identiques:

>>> a = "some_string" 
>>> b = "some_string" 
>>> a is b 
True 

Mais s'il y a un espace dans la chaîne, ils ne sont pas:

>>> a = "some string" 
>>> b = "some string" 
>>> a is b 
False 

Si ce comportement est normal, quelqu'un pourrait expliquer s'il vous plaît ce qui se passe.

Éditer: Clause de non-responsabilité! Ceci n'est pas utilisé pour vérifier l'égalité. En fait, je voulais expliquer à quelqu'un d'autre que «c'est» est seulement pour vérifier l'identité, pas l'égalité. Et de la documentation j'avais compris que les références créées de cette manière seraient différentes, qu'une nouvelle chaîne serait créée à chaque fois. Le tout premier exemple que j'ai donné m'a ébranlé quand je ne pouvais pas prouver mon propre point!

Edit: Je comprends que cela est pas un bug, et interné était un nouveau concept pour moi. This semble être une bonne explication.

+0

voir http: // stackoverflow.com/questions/306313/python-is-operator-se comporte-de façon inattendue-avec-entiers – cobbal

+0

"Bug?" Les questions m'énervent vraiment ... mais je suppose que ce n'est pas une raison pour marquer une question ... est-ce? – MattH

+0

@cobbal: C'est légèrement différent de ce qui se passe ici. –

Répondre

10

Python ou non automatiquement les chaînes internes, qui détermine si les futures instances de la chaîne partageront une référence.

S'il décide d'interner une chaîne, les deux feront référence à la même instance de chaîne. Si ce n'est pas le cas, cela créera deux chaînes distinctes qui auront le même contenu.

En général, vous n'avez pas à vous soucier de savoir si cela se produit ou non; vous voulez généralement vérifier l'égalité, a == b, pas si ce sont le même objet, a is b.

+0

+1 vraiment clair – Ant

+1

Juste par curiosité, savez-vous ce que la logique est quand Python internes des chaînes? Je pensais qu'il internait chaque littéral de chaîne mais apparemment pas ... – katrielalex

+0

@katrielalex: Les chaînes d'un fichier .py sont un peu différentes: elles sont stockées dans une liste de constantes qui sont référencées par index dans le bytecode. Cela signifie que si vous utilisez la même constante de chaîne à deux endroits dans un fichier .py, il est presque certain qu'ils seront le même objet. C'est différent de l'internat. Cependant, l'OP n'est pas à court d'un fichier .py, il s'exécute à partir de l'interpréteur Python; cela signifie qu'ils sont analysés en tant que "fichiers" distincts et n'ont pas de table de chaînes partagée. –

1

TIM PETERS SAID: Désolé, le seul bug que je vois ici est dans le code que vous avez posté en utilisant "est" pour essayer de déterminer si deux chaînes sont égales. Les tests "is" pour l'identité de l'objet, pas pour l'égalité, et pour savoir si deux objets immuables sont vraiment le même objet ne sont généralement pas définis par Python. Vous devriez utiliser "==" pour vérifier l'égalité de deux chaînes. La seule fois où il est fiable d'utiliser "est" dans ce but est lorsque vous avez explicitement interné toutes les chaînes comparées (via la fonction interne intern()).

d'ici: http://mail.python.org/pipermail/python-bugs-list/2004-December/026772.html

+0

-1: pour les objets immuables comme les chaînes, vous vous attendez à des références égales, donc ce n'est pas un bug. – Falcon

+0

@Falcon: Non. Les chaînes sont immuables * permet * l'internalisation (efficace) (= références identiques pour des objets identiques), mais elle ne l'exige pas. – delnan

+0

@Falcon: Eh bien, vous vous trompez dans cette attente. Vérification de l'égalité entre le code python natif et la bibliothèque c python-wrapped, par exemple: openssl library. C'est même si vous ne saviez pas que toutes les chaînes ne sont pas internées. Dommage que je ne puisse pas te marquer. – MattH

0

Cela devrait être plus d'un commentaire à la réponse de Gleen, mais je ne peux pas encore faire de commentaires. J'ai effectué quelques tests directement sur l'interpréteur Python et j'ai vu un comportement intéressant. Selon Glenn, l'interprète traite les entrées comme des «fichiers» distincts et ne partage pas une table de chaînes lorsqu'il est stocké pour référence future. Voici ce que je lance:

>>> a="some_string" 
>>> b="some_string" 
>>> id(a) 
2146597048 
>>> id(b) 
2146597048 
>>> a="some string" 
>>> b="some string" 
>>> id(a) 
2146597128 
>>> id(b) 
2146597088 
>>> c="some string" <-----(1) 
>>> d="some string" 
>>> id(c) 
2146597208   <-----(1) 
>>> a="some_string" 
>>> b="some_string" 
>>> id(a) 
2146597248   <---- waited a few minutes 
>>> c="some_string" 
>>> d="some_string" 
>>> id(d) 
2146597248   <---- still same id after a few min 
>>> b="some string" 
>>> id(b) 
2146597288 
>>> b="some_string" <---(2) 
>>> id(b) 
2146597248   <---(2) 
>>> a="some" 
>>> b="some" 
>>> c="some" 
>>> d="some"   <---(2) lost all references 
>>> id(a) 
2146601728 
>>> a="some_string" <---(2) 
>>> id(a) 
2146597248   <---(2) returns same old one after mere seconds 
>>> a="some" 
>>> id(a) 
2146601728   <---(2) Waited a few minutes 
>>> a="some_string" <---- (1) 
>>> id(a) 
2146597208   <---- (1) Reused a "different" id after a few minutes 

Il semble que certaines des références id peut être réutilisé après les références initiales sont perdues et ne sont plus « en utilisation » (1), mais il pourrait également être liée à la temps que ces références d'identification ne sont pas utilisées, comme vous pouvez le voir dans ce que j'ai marqué comme numéro (2), donnant des références d'identification différentes en fonction de combien de temps cet identifiant n'a pas été utilisé. Je trouve juste cela curieux et j'ai pensé à le poster.