“est” l'opérateur se comporte de manière inattendue avec des entiers
Pourquoi la suite de se comporter de façon inattendue en Python?
>>> a = 256
>>> b = 256
>>> a is b
True # This is an expected result
>>> a = 257
>>> b = 257
>>> a is b
False # What happened here? Why is this False?
>>> 257 is 257
True # Yet the literal numbers compare properly
Je suis à l'aide de Python 2.5.2. Essayer quelques-uns des différentes versions de Python, il semble que Python 2.3.3 ci-dessus montre les comportements entre 99 et 100.
Basé sur la ci-dessus, je peux émettre l'hypothèse que Python est en interne mis en œuvre, tels que les "petits" nombres entiers sont stockés d'une manière différente que les grands nombres entiers et la is
opérateur peut faire la différence. Pourquoi la fuite de l'abstraction? Quelle est la meilleure façon de comparer deux objets arbitraires pour voir si elles sont la même chose quand je ne sais pas à l'avance s'ils sont des nombres ou pas?
OriginalL'auteur Greg Hewgill | 2008-11-20
Vous devez vous connecter pour publier un commentaire.
Prendre un coup d'oeil à ceci:
EDIT: Voici ce que j'ai trouvé dans le Python 2 documentation, "Plaine Entier Des Objets" (C'est la même chose pour Python 3):
L'-5 est juste une heuristique pour la capture de commun négatif des espaces réservés, je pense. 0..255 couvre les tableaux de simples valeurs d'octets. Il est 256 c'est mystérieux, mais je suppose que c'est pour le montage et démontage des entiers dans/à partir d'octets.
Ce que je comprends de la gamme a été choisi en regardant les valeurs couramment utilisées dans plusieurs projets (et en plusieurs langues).
Selon reddit.com/r/Python/comments/18leav/..., la gamme utilisée pour [-5,100]. Il a été élargi pour inclure la gamme complète des valeurs d'octets plus de 256, parce que c'est sans doute un numéro commun.
OriginalL'auteur Cybis
En résumé - permettez-moi de souligner: Ne pas utiliser
is
pour comparer des nombres entiers.Ce n'est pas le comportement que vous devez avoir toutes les espérances au sujet.
Au lieu de cela, utiliser
==
et!=
de comparer pour l'égalité et l'inégalité, respectivement. Par exemple:Explication
De savoir cela, vous devez connaître les éléments suivants.
D'abord, qu'est -
is
faire? C'est un opérateur de comparaison. À partir de la la documentation:Et donc les suivantes sont équivalentes.
De la la documentation:
Noter que le fait que l'id d'un objet dans Disponible (l'implémentation de référence de Python) est l'emplacement dans la mémoire est un détail d'implémentation. D'autres implémentations de Python (comme Python ou IronPython) pourrait facilement avoir une mise en œuvre différente pour
id
.Quel est donc le cas d'utilisation pour
is
? PEP8 décrit:La Question
Vous demandez, et l'état, la question suivante (avec code):
Il est pas un résultat attendu. Pourquoi est-il prévu? Cela signifie seulement que les nombres entiers sont évalués à
256
référencé par les deuxa
etb
sont la même instance de l'entier. Les entiers sont immuables en Python, donc ils ne peuvent pas changer. Cela ne devrait pas avoir d'impact sur le code. Il ne devrait pas être prévu. C'est qu'un détail d'implémentation.Mais peut-être que nous devrions être heureux qu'il n'y a pas une nouvelle instance en mémoire à chaque fois que nous l'état d'un montant égal à 256.
Ressemble, nous avons maintenant deux instances distinctes de nombres entiers avec la valeur de
257
dans la mémoire. Puisque les nombres entiers sont immuables, ce déchets de la mémoire. Espérons que nous ne sommes pas perdre beaucoup de lui. Nous ne serons probablement pas. Mais ce comportement n'est pas garanti.Bien, cela ressemble à votre mise en œuvre de Python est d'essayer d'être intelligent et ne pas créer évalués de manière redondante des nombres entiers en mémoire, sauf si elle a pour. Vous semblez indiquer que vous êtes en utilisant le référent de la mise en œuvre de Python, qui est Disponible. Bon pour Disponible.
Il pourrait être encore mieux si Disponible pourrait faire cela à l'échelle mondiale, si elle pouvait le faire à bon marché (comme il y aurait un coût dans la recherche), peut-être une autre implémentation.
Mais comme pour l'impact sur le code, vous ne devriez pas les soins si un nombre entier est un cas particulier d'un entier. Vous devez seulement garde à ce que la valeur de cette instance, et vous devez utiliser la normale des opérateurs de comparaison pour cela, c'est à dire
==
.Ce
is
neis
vérifie que leid
de deux objets sont les mêmes. Dans Disponible, leid
est l'emplacement dans la mémoire, mais il pourrait être un autre numéro d'identification unique dans une autre mise en œuvre. Pour rappeler ce avec le code:est le même que
Pourquoi nous voulons utiliser
is
alors?Cela peut être un très rapides par rapport à-dire, vérifier si les deux très longues chaînes sont égales en valeur. Mais puisqu'il s'applique à l'unicité de l'objet, nous avons donc limité des cas d'utilisation. En fait, nous voulons surtout l'utiliser pour vérifier
None
, qui est un singleton (une seule instance existante dans un endroit de la mémoire). On pourrait créer d'autres célibataires s'il est possible de faire un amalgame entre eux, que l'on pourrait vérifier avecis
, mais ils sont relativement rares. Voici un exemple (en Python 2 et 3), par exempleQui imprime:
Et nous le voyons donc, avec
is
et une sentinelle, nous sommes en mesure de différencier entre le moment oùbar
est appelé sans argument, et lorsqu'elle est appelée avecNone
. Tels sont les principaux cas d'utilisation pouris
- faire pas l'utiliser pour tester l'égalité des entiers, des chaînes, tuples, ou d'autres choses comme celles-ci.is
- ne pas l'utiliser pour tester l'égalité des entiers, des chaînes, tuples, ou d'autres choses comme celles-ci." Cependant, je suis en train d'intégrer un simple état de la machine dans ma classe, et depuis les états-unis sont opaques valeurs dont la seule propriété observable, c'est que d'être identiques ou différents, il semble tout à fait naturel pour eux d'être comparable avecis
. J'ai l'intention d'utiliser l'internement des chaînes de caractères comme des états. J'aurais préféré de la plaine des entiers, mais malheureusement, Python ne peut pas stagiaire entiers (0 is 0
est un détail d'implémentation).les sons que vous avez besoin de les énumérations? stackoverflow.com/questions/37601644/...
Peut-être, de grâce, ne savent pas eux. Ce pourrait être plus approprié pour vous répondre de l'OMI.
Peut-être l'aide d'un certain nombre d'objets muets comme la sentinelle dans votre réponse serait un plus léger de la solution...
les énumérations sont dans la bibliothèque standard de Python 3, et qui serait probablement encourager votre code pour être un peu plus constructif que de nu sentinelles.
OriginalL'auteur Aaron Hall
Cela dépend si vous êtes à la recherche pour voir si les 2 choses sont égales, ou le même objet.
is
vérifie pour voir si elles sont le même objet, non seulement de l'égalité. La petite ints sont probablement pointant vers le même emplacement de mémoire pour l'efficacité de l'espaceVous devez utiliser
==
pour comparer l'égalité d'objets arbitraires. Vous pouvez spécifier le comportement avec les__eq__
, et__ne__
attributs.OriginalL'auteur JimB
Je suis en retard, mais, vous voulez qu'une source de votre réponse?*
Bonne chose à propos de Disponible, c'est que vous pouvez réellement voir la source pour cela. Je vais utiliser des liens pour le
3.5
communiqué pour le moment; trouver le correspondant2.x
est trivial.Dans Disponible, le
C-API
fonction qui gère la création d'un nouveauint
objet estPyLong_FromLong longue(v)
. La description de cette fonction est:Ne sais pas vous, mais je vois cela et pense que: nous allons trouver que la matrice de!
Si vous n'avez pas trafiqué avec la
C
d'application du code des Disponible vous devriez, tout est très organisé et lisible. Pour notre cas, nous avons besoin de regarder dans leObjets/
sous-répertoire de la code source principal de l'arbre de répertoire.PyLong_FromLong
traitelong
objets de sorte qu'il ne devrait pas être difficile d'en déduire que nous avons besoin de jeter un regard à l'intérieur delongobject.c
. Après avoir regardé à l'intérieur, vous pourriez penser que les choses sont chaotiques; ils sont, mais n'ayez crainte, la fonction nous sommes à la recherche pour est froid à230
en attente pour nous de le vérifier. C'est une petite fonction de sorte que le corps principal (à l'exclusion des déclarations) est facilement collé ici:Maintenant, nous ne sommes pas
C
maître-code-haxxorz mais nous sommes également pas dumb, nous pouvons voir queCHECK_SMALL_INT(ival);
jeter un oeil à nous tous séduisante; nous pouvons comprendre qu'il a quelque chose à voir avec cela. Let's check it out:Donc, c'est une macro qui appelle la fonction
get_small_int
si la valeurival
satisfait la condition:Quels sont donc
NSMALLNEGINTS
etNSMALLPOSINTS
? Si vous avez deviné macros vous n'obtenez rien parce que ce n'était pas une question difficile.. De toute façon, ici, ils sont:Si notre condition est
if (-5 <= ival && ival < 257)
appelget_small_int
.Pas d'autre endroit où aller, mais continuons notre voyage en regardant
get_small_int
dans toute sa splendeur (eh bien, nous allons regarder à corps c'est parce que c'est là que les choses intéressantes sont):D'accord, déclarer un
PyObject
, affirmer que la condition précédente est titulaire et d'exécuter la mission:small_ints
ressemble beaucoup à ce tableau, nous avons été à la recherche pour.. et, il est! Nous pourrions viens de lire la putain de la documentation et nous avons connaître tout le long!:Donc ouais, c'est notre gars. Lorsque vous souhaitez créer un nouveau
int
dans la gamme[NSMALLNEGINTS, NSMALLPOSINTS)
vous aurez juste revenir une référence à un objet qui a été préaffectés.Depuis que la référence se rapporte au même objet, l'émission de
id()
directement ou vérification d'identité avecis
sur qu'il sera de retour à exactement la même chose.Mais, quand sont-ils répartis??
Lors de l'initialisation
_PyLong_Init
Python fera un plaisir d'entrer dans une boucle for ne le faire pour vous:J'espère que mon explication vous a fait
C
(jeu de mots évidemment destiné) les choses clairement maintenant.Mais, 257 257 est? Qu'est-ce?
C'est effectivement plus facile à expliquer, et j'ai tenté de le faire déjà; elle est due au fait que Python va exécuter cette déclaration interactive:
comme un seul bloc. Au cours de complilation de cette déclaration, Disponible verrez que vous avez deux correspondants littéraux, et d'utiliser la même
PyLongObject
représentant257
. Vous pouvez voir si vous ne la compilation de vous-même et examiner son contenu:Disponible lorsque l'opération; il est maintenant tout va charger exactement le même objet:
Donc
is
sera de retourTrue
.* -- je vais essayer de mot et de plus en plus d'introduction, de manière de plus pour être en mesure de la suivre.
OriginalL'auteur Jim Fasarakis Hilliard
Comme vous pouvez le vérifier en fichier source intobject.c, Python caches petits entiers pour plus d'efficacité. Chaque fois que vous créez une référence à un entier plus petit, vous faites référence à la mise en cache petites entier, pas un nouvel objet. 257 n'est pas un entier plus petit, de sorte qu'il est calculé comme un objet différent.
Il est préférable d'utiliser
==
à cette fin.OriginalL'auteur Angel
Je pense que vos hypothèses sont correctes. Expérience avec
id
(identité de l'objet):Il semble que les numéros de
<= 255
sont traités comme des littéraux et rien au-dessus est traité différemment!OriginalL'auteur Amit
Pour immuable des objets de valeur, comme des entiers, des chaînes ou des datetimes, l'identité de l'objet n'est pas particulièrement utile. Il est préférable de penser à propos de l'égalité. L'identité est essentiellement un détail d'implémentation pour des objets de valeur - comme ils sont immuables, il n'y a aucune différence entre le fait d'avoir plusieurs références au même objet ou plusieurs objets.
OriginalL'auteur babbageclunk
is
est l'identité de l'opérateur d'égalité (fonctionnement commeid(a) == id(b)
); c'est juste que les deux chiffres ne sont pas nécessairement le même objet. Pour des raisons de performances, certains petits entiers se trouvent être memoized de sorte qu'ils ont tendance à être les mêmes (ce qui peut être fait depuis qu'ils sont immuables).PHP
===
opérateur, d'autre part, est décrite comme la vérification de l'égalité et de type:x == y and type(x) == type(y)
comme par Paulo Freitas commentaire. Cela ne sera pas suffisant pour le commun des nombres, mais diffèrent deis
pour les classes qui définissent__eq__
dans une absurde:PHP apparemment permet la même chose pour "built-in" des classes (qui, pour moi, signifie en œuvre au niveau C, pas en PHP). Un peu moins absurde utilisez peut-être un objet timer, qui a une valeur différente à chaque fois qu'il est utilisé comme un nombre. Tout à fait pourquoi vous voulez émuler Visual Basic
Now
au lieu de montrer que c'est une évaluation avectime.time()
je ne sais pas.Greg Hewgill (OP) fait une clarification de commentaire "Mon objectif est de comparer l'identité de l'objet, plutôt que de l'égalité de valeur. Sauf pour les nombres, où je veux traiter de l'identité de l'objet même que l'égalité de valeur."
Ce serait encore une autre réponse, comme nous l'avons à catégoriser les choses comme des numéros ou non, de choisir si l'on compare avec
==
ouis
. Disponible définit la numéro de protocole, y compris PyNumber_Check, mais ce n'est pas accessible à partir de Python lui-même.On pourrait essayer d'utiliser
isinstance
avec tous les types de nombre que nous connaissons, mais ce sera inévitablement incomplète. Les types de module contient un StringTypes liste, mais pas de NumberTypes. Depuis la version 2.6 de Python, est construit dans le nombre de classes qui ont une classe de basenombres.Nombre
, mais il a le même problème:Par la voie, NumPy produira des instances séparées de leur faible nombre.
Je ne sais pas vraiment une réponse à cette variante de la question. Je suppose que l'on pourrait théoriquement utiliser ctypes appeler
PyNumber_Check
, mais même que la fonction a été débattu, et ce n'est certainement pas portable. Nous devons simplement être moins particulier à propos de ce que nous avons test pour l'instant.En fin de compte, cette question découle de Python à l'origine, pas d'avoir un type d'arbre avec des prédicats comme Schéma de l'
number?
, ou Haskell type de classe Num.is
vérifie l'identité de l'objet, pas la valeur de l'égalité. PHP a une histoire colorée, où===
apparemment se comporte commeis
seulement sur les objets en PHP5, mais pas en PHP4. Tels sont les douleurs de croissance de déplacement à travers les langues (y compris les versions d'un seul).OriginalL'auteur Yann Vernier
Il arrive aussi avec des cordes:
Maintenant tout semble aller bien.
Que l'on attend trop.
Maintenant que c'est inattendu.
'xx'
est comme prévu, comme c'est'xxx'
, mais'x x'
ne l'est pas.C'est parce qu'il ressemble à un symbole si il n'y a pas d'espace. Les noms sont automatiquement internés, donc si il y a quelque chose nommé
xx
n'importe où dans votre Python session, que la chaîne est déjà internés; et il y a peut être une heuristique qui le fait, si elle ressemble à un nom. Comme avec les nombres, ce qui peut être fait parce qu'ils sont immuables. docs.python.org/2/library/functions.html#intern guilload.com/python-string-interningMerci pour le partage de chaîne python stage blog, je viens de tout lire et j'ai adoré. Python est tellement incroyable 🙂
OriginalL'auteur sobolevn
Il y a un autre problème qui n'est pas souligné dans l'une des questions /réponses. Python est autorisé à fusionner les deux valeurs inaltérables, et pré-créé de petites int les valeurs ne sont pas la seule façon, cela peut arriver. Un Python de mise en œuvre n'est jamais garanti pour ce faire, mais ils font tous pour plus que juste des petits ints.
Pour une chose, il ya quelques autres pré-créé des valeurs telles que le vide
tuple
,str
, etbytes
, et quelques courtes chaînes de caractères (Disponible 3.6, c'est l'256 unique de caractères Latin-1 chaînes de caractères). Par exemple:Mais aussi, même les non-pré-créé valeurs peuvent être identiques. Considérez ces exemples:
Et ce n'est pas limité à
int
valeurs:Évidemment, Disponible ne vient pas avec un pré-créé
float
valeur pour42.23e100
. Donc, ce qui se passe ici?Disponible le compilateur va fusionner les valeurs des constantes de certains connus-immuable des types comme
int
,float
,str
,bytes
, dans la même unité de compilation. Pour un module, le module est une unité de compilation, mais à la interactives interprète, chaque instruction distincte de l'unité de compilation. Depuisc
etd
sont définies dans des déclarations séparées, leurs valeurs ne sont pas fusionnés. Depuise
etf
sont définies dans la même déclaration, leurs valeurs sont regroupées.Vous pouvez voir ce qui se passe par le démontage du bytecode. Essayez de définir une fonction qui ne
e, f = 128, 128
et puis l'appel dedis.dis
sur elle, et vous allez voir qu'il y a une seule valeur de la constante(128, 128)
Vous remarquerez peut-être que le compilateur a stocké
128
comme une constante, même si elle n'est pas réellement utilisée par le bytecode, qui vous donne une idée de la façon dont peu d'optimisation Disponible du compilateur. Ce qui signifie que (non vide) de n-uplets fait de ne pas fusionné:Mettre que dans une fonction,
dis
, et à regarder leco_consts
—il y a un1
et un2
, deux(1, 2)
tuples qui partagent le même1
et2
mais ne sont pas identiques, et une((1, 2), (1, 2))
tuple qui a deux distincts de l'égalité des n-uplets.Il y a une optimisation plus que Disponible: chaîne de stage. Contrairement au compilateur de constantes, ce n'est pas restreinte à code source de littéraux:
D'autre part, elle est limitée à la
str
type, et pour les chaînes de stockage interne de type ascii "compact", "compact", ou "legacy prêt", et dans de nombreux cas seulement ascii "compact" aura interné.En tout cas, les règles pour quelles valeurs doivent être, peut-être, ou ne peut pas être distinctes varier de mise en œuvre de la mise en œuvre, et entre les différentes versions de la même application, et peut-être même entre deux exécutions du même code sur la même copie de la même mise en œuvre.
Il peut être vaut la peine d'apprendre les règles d'un Python pour le plaisir. Mais c'est pas la peine de compter sur eux dans votre code. La seule règle est:
Ou, en d'autres termes, seule l'utilisation
is
de test pour la documentation des singletons (commeNone
) ou qui sont créés uniquement dans un endroit dans le code (comme le_sentinel = object()
idiome).OriginalL'auteur abarnert
Prendre un coup d'oeil ici
OriginalL'auteur user5319825