is
verifica objeto de identidad, y cualquier aplicación de Python, cuando se reúna literal de tipos inmutables, es perfectamente libre de ya sea crea un nuevo objeto de ese tipo inmutable, o buscan a través de objetos existentes de ese tipo a ver si algunos de ellos podrían reutilizarse (agregando una nueva referencia al mismo objeto subyacente). Esta es una elección pragmática de optimización y no sujeta a restricciones semánticas, por lo que su código nunca debe depender de qué ruta puede tomar una implementación de entrega (¡o podría romperse con una versión de reparación/optimización de Python!).
Considérese, por ejemplo:
>>> import dis
>>> def f():
... x = 'google.com'
... return x is 'google.com'
...
>>> dis.dis(f)
2 0 LOAD_CONST 1 ('google.com')
3 STORE_FAST 0 (x)
3 6 LOAD_FAST 0 (x)
9 LOAD_CONST 1 ('google.com')
12 COMPARE_OP 8 (is)
15 RETURN_VALUE
por lo que en esta implementación particular, dentro de una función, su observación no se aplica y se hace solamente un objeto para el literal (cualquier literal), y, en efecto:
>>> f()
True
pragmático eso es porque dentro de una función que hace un paso a través de la tabla local de constantes (para ahorrar espacio en la memoria no hacer múltiples objetos inmutables constantes donde uno es suficiente) es bastante es barato y rápido, y puede ofrecer un buen rendimiento ya que la función puede ser llamada repetidamente después.
embargo, la misma aplicación, desde el modo interactivo (Editar: Al principio pensé que esto también sucedería en el nivel superior de un módulo, pero un comentario de @Thomas me puso la derecha, véase más adelante):
>>> x = 'google.com'
>>> y = 'google.com'
>>> id(x), id(y)
(4213000, 4290864)
NO se molesta en intentar guardar la memoria de esa manera - los id
s son diferentes, es decir, objetos distintos. Hay costos potencialmente más altos y rendimientos más bajos, por lo que la heurística del optimizador de esta implementación le indica que no se moleste en buscar y solo siga adelante. por ejemplo, en el nivel superior del módulo, y por observación @Thomas', teniendo en cuenta::
Editar
$ cat aaa.py
x = 'google.com'
y = 'google.com'
print id(x), id(y)
más vemos la memoria de optimización basado en tablas-de-constantes en esta implementación:
>>> import aaa
4291104 4291104
(final de Edición por observación de @Thomas ').
Por último, de nuevo en la misma aplicación:
>>> x = 'google'
>>> y = 'google'
>>> id(x), id(y)
(2484672, 2484672)
las heurísticas son diferentes aquí porque la cadena literal "parece que podría ser un identificador" - por lo que podría ser utilizado en la operación que requiere internar .. .por lo que el optimizador lo interna de todos modos (y una vez internado, buscarlo se vuelve muy rápido, por supuesto). Y, en efecto, sorpresa, sorpresa ...:
>>> z = intern(x)
>>> id(z)
2484672
... x
tiene sido intern
ed primera vez (como se ve, el valor de retorno de intern
es el mismo objeto comox
y y
, ya que tiene el mismo id()
). Por supuesto, tampoco debe confiar en esto: el optimizador no tiene tiene para internar todo automáticamente, es solo una heurística de optimización; si necesita intern
cadena ed, intern
explícitamente, solo para estar seguros. Cuando haces cadenas intern ... explícitamente:
>>> x = intern('google.com')
>>> y = intern('google.com')
>>> id(x), id(y)
(4213000, 4213000)
... entonces hace garantizar exactamente el mismo objeto (es decir, los mismos resultados id()
) cada uno y cada vez - para que pueda aplicar micro -optimizaciones como comprobar con is
en lugar de ==
(casi nunca he encontrado la ganancia de rendimiento minúsculo que merezca la pena ;-).
Editar: sólo para aclarar, he aquí el tipo de diferencias de rendimiento que estoy hablando, en un lento Macbook Air ...:
$ python -mtimeit -s"a='google';b='google'" 'a==b'
10000000 loops, best of 3: 0.132 usec per loop
$ python -mtimeit -s"a='google';b='google'" 'a is b'
10000000 loops, best of 3: 0.107 usec per loop
$ python -mtimeit -s"a='goo.gle';b='goo.gle'" 'a==b'
10000000 loops, best of 3: 0.132 usec per loop
$ python -mtimeit -s"a='google';b='google'" 'a is b'
10000000 loops, best of 3: 0.106 usec per loop
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a is b'
10000000 loops, best of 3: 0.0966 usec per loop
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a == b'
10000000 loops, best of 3: 0.126 usec per loop
... unas pocas decenas de nanosegundos, ya sea manera, a lo sumo. Por lo tanto, vale la pena incluso pensando sólo en el extremo "optimizar el [eliminó impropio] fuera de este [embrollo suprimido] cuello de botella de rendimiento" situaciones! -)
Nice catch. Eso es extraño. –
Ambos son 'False' en Python 2.5.2. –
En ActivePython 2.5.4.4, se ven los mismos resultados que OP. Casi seguro tiene algo que ver con el interrogatorio de cuerdas, ¿verdad? –