70 votes

Comment le mot clé " is " est-il implémenté en Python ?

... le is qui peut être utilisé pour l'égalité dans les chaînes de caractères.

>>> s = 'str'
>>> s is 'str'
True
>>> s is 'st'
False

J'ai essayé les deux __is__() et __eq__() mais ça n'a pas marché.

>>> class MyString:
...   def __init__(self):
...     self.s = 'string'
...   def __is__(self, s):
...     return self.s == s
...
>>>
>>>
>>> m = MyString()
>>> m is 'ss'
False
>>> m is 'string' # <--- Expected to work
False
>>>
>>> class MyString:
...   def __init__(self):
...     self.s = 'string'
...   def __eq__(self, s):
...     return self.s == s
...
>>>
>>> m = MyString()
>>> m is 'ss'
False
>>> m is 'string' # <--- Expected to work, but again failed
False
>>>

143voto

Jochen Ritzel Points 42916

Test des chaînes de caractères avec is ne fonctionne que lorsque les chaînes de caractères sont internées. A moins que vous ne sachiez vraiment ce que vous faites et que vous ayez explicitement interné les cordes que vous devez jamais utiliser is sur les cordes.

is des tests pour identité pas égalité . Cela signifie que Python compare simplement l'adresse mémoire dans laquelle réside un objet. is répond essentiellement à la question "Dois-je avoir deux noms pour le même objet ?". - La surcharge de cette fonction n'aurait aucun sens.

Par exemple, ("a" * 100) is ("a" * 100) est Faux . Habituellement, Python écrit chaque chaîne dans un emplacement mémoire différent, ce qui se produit surtout pour les chaînes littérales.

14 votes

J'ai observé dans le passé que l'internage des chaînes de caractères peut se produire pour les valeurs calculées et les valeurs d'entrée de l'exécution si elles sont suffisamment courtes. 'a' * 100 n'est pas 'a' * 100 ; mais 'a' * 20 est 'a' * 20. Par ailleurs, 'a'.upper() n'est pas 'a'.upper(). Jython, IronPython, PyPy et d'autres peuvent internaliser de manière plus agressive. En bref, cela dépend de l'implémentation. L'appel de la fonction 'intern()' sur des chaînes de caractères "forcera" une chaîne de caractères à avoir la même identité d'objet que toute chaîne de caractères équivalente et précédemment internée, comme vous le dites. Cependant, je ne connais pas de cas d'utilisation valide pour tester l'identité des chaînes de caractères. (Performances possibles mises à part).

6 votes

("a" * 100) is ("a" * 100) pourrait être faux en 2010, mais aujourd'hui c'est vrai.

1 votes

@goteguru, pas pour moi, en 2019, avec CPython 3.5.6. Je pense que le commentaire de Jim de 2010 est le vrai gagnant : C'est la dépendance à la mise en œuvre. Ne rien supposer.

26voto

Phil H Points 10133

Le site is est équivalent à la comparaison de id(x) valeurs. Par exemple :

>>> s1 = 'str'
>>> s2 = 'str'
>>> s1 is s2
True
>>> id(s1)
4564468760
>>> id(s2)
4564468760
>>> id(s1) == id(s2)  # equivalent to `s1 is s2`
True

id est actuellement implémenté pour utiliser des pointeurs comme comparaison. Vous ne pouvez donc pas surcharger is lui-même, et AFAIK vous ne pouvez pas surcharger id soit.

Donc, vous ne pouvez pas. C'est inhabituel en Python, mais c'est ainsi.

1 votes

Vous pouvez surcharger id mais pas dans le sens où vous l'entendez probablement. Faites juste id = <function> .

0 votes

Non, ce n'est pas le cas. Essayez print(id(a.T) is id(a.T)) en python et vous verrez.

1 votes

@logicOnAbstractions Je crois qu'il veut dire comparer les identifiants avec == et non avec is . Donc print(id(a.T) == id(a.T)) devrait être équivalent à print(a is a) .

16voto

Jim Dennis Points 5454

Le Python is teste l'identité des objets. Vous ne devez PAS l'utiliser pour tester l'égalité des chaînes de caractères. Il peut sembler fonctionner fréquemment car les implémentations Python, comme celles de nombreux langages de très haut niveau, effectuent un "internage" des chaînes de caractères. En d'autres termes, les littéraux et les valeurs des chaînes sont conservés en interne dans une liste hachée et ceux qui sont identiques sont rendus comme des références au même objet. (Ceci est possible car les chaînes Python sont immuables).

Cependant, comme pour tout détail d'implémentation, vous ne devez pas vous y fier. Si vous voulez tester l'égalité, utilisez l'opérateur ==. Si vous voulez vraiment tester l'identité d'un objet, utilisez l'opérateur ==. is --- et j'aurais du mal à trouver un cas où vous devriez vous préoccuper de l'identité des objets de type chaîne. Malheureusement, vous ne pouvez pas compter sur le fait que deux chaînes soient d'une manière ou d'une autre des références d'objets "intentionnellement" identiques à cause de l'internage mentionné plus haut.

0 votes

Le seul endroit en Python où vous voulez faire une comparaison d'identité est lors de la comparaison avec des singletons (par exemple None) et des valeurs sentinelles qui doivent être uniques. En dehors de cela, il n'y a probablement presque aucune raison de le faire.

2 votes

@Lie Ryan : Je suis plutôt d'accord. Je ne l'utilise que pour None et pour des sentinelles spéciales que j'ai créées (généralement comme des appels à la base 'object()'). Cependant, je ne me sens pas à l'aise pour affirmer qu'il n'y a pas d'autres utilisations valides de l'opérateur 'is' ; juste aucune à laquelle je puisse penser. (Ce qui témoigne peut-être de ma propre ignorance).

10voto

pycruft Points 8095

Le site is compare les objets (ou, plutôt, compare si deux références sont au même objet).

C'est, je pense, pourquoi il n'y a pas de mécanisme pour fournir votre propre implémentation.

Cela fonctionne parfois avec les chaînes de caractères car Python stocke les chaînes de caractères de manière "intelligente", de sorte que lorsque vous créez deux chaînes de caractères identiques, elles sont stockées dans un seul objet.

>>> a = "string"
>>> b = "string"
>>> a is b
True
>>> c = "str"+"ing"
>>> a is c
True

Vous pouvez, je l'espère, voir la comparaison entre la référence et les données dans un simple exemple de "copie" :

>>> a = {"a":1}
>>> b = a
>>> c = a.copy()
>>> a is b
True
>>> a is c
False

5voto

modchan Points 1322

Si vous n'avez pas peur de vous embrouiller avec le bytecode, vous pouvez intercepter et patcher COMPARE_OP avec 8 ("is") pour appeler votre fonction de crochet sur les objets comparés. Regardez dis documentation du module pour start-in.

Et n'oubliez pas d'intercepter __builtin__.id() aussi si quelqu'un veut bien faire id(a) == id(b) au lieu de a is b .

1 votes

C'est intéressant de le savoir, c'est tout un monde de possibilités pour jouer avec les fonctions de python auxquelles je n'avais jamais pensé. Mais pourquoi ce jamais être une bonne idée ?

0 votes

Dans mon entreprise, nous avons une bibliothèque de test interne contenant un décorateur de contexte qui fige le temps en remplaçant datetime.datetime par une implémentation qui renvoie toujours une heure spécifique à partir de utcnow(). Si vous exécutez datetime.datetime.utcnow() et que vous essayez de récupérer la valeur renvoyée, cela échouera parce que sa classe est incohérente (elle prétend être une autre classe). Dans ce cas, en surchargeant la méthode is pourrait être une solution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X