2010-06-07 15 views
52

... la palabra clave is que se puede usar para la igualdad en cadenas.¿Cómo se implementa la palabra clave 'is' en Python?

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

He intentado tanto __is__() y __eq__() pero no funcionó.

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

Respuesta

107

cadenas de prueba con is sólo funciona cuando están internados los hilos. A menos que realmente sepa lo que está haciendo y explícitamente interned las cadenas debe nunca use is en cadenas.

is pruebas de identidad , no la igualdad. Eso significa que Python simplemente compara la dirección de memoria en la que reside un objeto. is responde básicamente a la pregunta "¿Tengo dos nombres para el mismo objeto?" - Sobrecarga que no tendría sentido.

Por ejemplo, ("a" * 100) is ("a" * 100) es False. Por lo general, Python escribe cada cadena en una ubicación de memoria diferente, la internación ocurre principalmente para los literales de cadena.

+8

que he observado en el pasado que internación cadena puede suceder para que el tiempo de ejecución calculado los valores de entrada y si son lo suficientemente corto. 'a' * 100 no es 'a' * 100; pero 'a' * 20 es "a" * 20. Mientras tanto 'a'.upper() no es' a'.upper(). Jython, IronPython, PyPy y otros pueden internar de manera más agresiva. En resumen, depende de la implementación. Llamar a la función 'intern()' en las cadenas "forzará" a una cadena a tener la misma identidad de objeto que cualquier cadena de caracteres equivalente y previamente interna() 'd, como dices. Sin embargo, no conozco un caso de uso válido para probar la identidad de la cadena. (Posible rendimiento aparte). –

8

La palabra clave is compara objetos (o, mejor dicho, compara si dos referencias son para el mismo objeto).

Cuál es, creo, por qué no hay un mecanismo para proporcionar su propia implementación.

Suele funcionar a veces en cadenas porque Python almacena las cadenas 'inteligentemente', de modo que cuando se crean dos cadenas idénticas se almacenan en un objeto.

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

Puede espero que vea la referencia vs comparación de datos en un ejemplo simple 'copia':

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

El operador is es equivalente a comparar id(x) valores. id actualmente se implementa para usar punteros como la comparación. Por lo tanto, no puede sobrecargar is, y AFAIK tampoco puede sobrecargar id.

Entonces, no puedes. Inusual en Python, pero ahí está.

+1

Puede sobrecargar 'id', pero no en el sentido que probablemente quiso decir. Solo haz 'id = '. – HyperNeutrino

13

La palabra clave Python is prueba la identidad del objeto. NO debes usarlo para probar la igualdad de cuerdas. Puede parecer que funciona con frecuencia porque las implementaciones de Python, como las de muchos lenguajes de muy alto nivel, realizan "interning" de cadenas de caracteres. Es decir que los literales y valores de cadena se mantienen internamente en una lista hash y los que son idénticos se representan como referencias al mismo objeto. (Esto es posible porque las cadenas de Python son inmutables).

Sin embargo, como con cualquier detalle de implementación, no debe confiar en esto. Si desea probar la igualdad, use el operador ==. Si realmente quieres probar la identidad del objeto, utiliza is --- y me costaría mucho crear un caso en el que te interese la identidad del objeto de cadena. Lamentablemente, no se puede contar si dos cadenas son, de alguna manera, referencias de objetos "intencionalmente" idénticas debido a la internación antes mencionada.

+0

el único lugar en Python donde desea hacer una comparación de identidad es cuando compara con Singletons (por ejemplo, Ninguno) y los valores centinela que deben ser únicos. Aparte de eso, probablemente no haya casi ninguna razón para hacerlo. –

+2

@Lie Ryan: tiendo a estar de acuerdo. Solo lo uso para None y para los centinelas especiales que he creado (generalmente como llamadas a la base 'object()'). Sin embargo, no me siento cómodo afirmando que no hay otros usos válidos para el operador 'es'; solo ninguno en lo que puedo pensar (Posiblemente un testimonio de mi propia ignorancia). –

5

Si no tiene miedo de estropear el bytecode, puede interceptar y parchear COMPARE_OP con el argumento 8 ("is") para llamar a su función de gancho en los objetos que se comparan. Consulte la documentación del módulo dis para el inicio.

Y no se olvide de interceptar __builtin__.id() también si alguien va a hacer id(a) == id(b) en lugar de a is b.

+1

Es interesante saber que hay un mundo de posibilidades para jugar con la función de Python en el que nunca había pensado. Pero, ¿por qué sería esto una buena idea? – alexis

+0

En mi empresa, tenemos una biblioteca de pruebas interna que contiene un decorador de contexto que congela el tiempo al reemplazar datetime.datetime por una implementación que siempre devuelve un tiempo específico desde utcnow(). Si ejecuta datetime.datetime.utcnow() e intenta recuperar el valor devuelto, fallará porque su clase es incoherente (se trata de otra clase). En este caso, anular la forma en que 'is' funciona podría ser una solución. –

2

no puede comparar una variable de cadena con un valor de cadena y dos variables de cadena cuando la cadena comienza con '-'. Mi versión de Python es 2.6.6

>>> s = '-hi' 
>>> s is '-hi' 
False 
>>> s = '-hi' 
>>> k = '-hi' 
>>> s is k 
False 
>>> '-hi' is '-hi' 
True 
1

Usted no puede sobrecargar el operador is. Lo que desea sobrecargar es el operador ==. Esto se puede hacer definiendo un método __eq__ en la clase.

1

Está utilizando la comparación de identidad. == es probablemente lo que quieres. La excepción a esto es cuando desea verificar si un elemento y otro son el mismo objeto EXACTO y en la misma posición de memoria. En los ejemplos, los elementos no son los mismos, ya que uno es de un tipo diferente (my_string) que el otro (cadena). Además, no existe tal cosa como una clase. __is__ en python (a menos que, por supuesto, lo pongas allí mismo). Si existiera, al comparar objetos con es no sería confiable simplemente comparar las ubicaciones de la memoria.

La primera vez que me encontré con la palabra clave es, me confundió también. Pensé que es y == no eran diferentes. Produjeron el mismo resultado del intérprete en muchos objetos. Este tipo de suposición es EXACTAMENTE con lo que es ... es para. Es el equivalente de pitón "Oye, no confundas estos dos objetos, son diferentes", que es esencialmente lo que dijo [quien sea que me enderezó]. Encabezado de manera muy diferente, pero un punto == el otro punto.

la de algunos ejemplos útiles y algo de texto para ayudar con las diferencias, a veces confusos visita a document from python.org's mail host escrito por "Danny Yoo"

o, si eso es fuera de línea, utilice el unlisted pastebin que hice de él es cuerpo.

en caso de que, en algunos más o menos 20 lunas azules (lunas azules son un hecho real), son a la vez hacia abajo, voy a citar los ejemplos de código

### 
>>> my_name = "danny" 
>>> your_name = "ian" 
>>> my_name == your_name 
0    #or False 
### 

### 
>>> my_name[1:3] == your_name[1:3] 
1 #or True 
### 

### 
>>> my_name[1:3] is your_name[1:3] 
0 
### 
0

errores de aserción pueden surgir fácilmente con es palabra clave al comparar objetos. Por ejemplo, los objetos a y b pueden tener el mismo valor y compartir la misma dirección de memoria.Por lo tanto, haciendo un

>>> a == b 

va a evaluar a

True 

Pero si

>>> a is b 

evalúa a

False 

probablemente debería comprobar

>>> type(a) 

y

>>> type(b) 

Estos podrían ser diferentes y una razón para el fracaso.

1

'is' compara la identidad del objeto mientras que == compara los valores.

Ejemplo:

a=[1,2] 
b=[1,2] 
#a==b returns True 
#a is b returns False 

p=q=[1,2] 
#p==q returns True 
#p is q returns True 
Cuestiones relacionadas