python - separar - el operador ''es'' se comporta de manera diferente al comparar cadenas con espacios
python separar string por caracter (5)
Empecé a aprender Python (Python 3.3) y estaba probando el operador is
. Intenté esto:
>>> b = ''is it the space?''
>>> a = ''is it the space?''
>>> a is b
False
>>> c = ''isitthespace''
>>> d = ''isitthespace''
>>> c is d
True
>>> e = ''isitthespace?''
>>> f = ''isitthespace?''
>>> e is f
False
Parece que el espacio y el signo de interrogación hacen que el comportamiento sea diferente. ¿Que esta pasando?
EDITAR: Sé que debería usar ==
, solo quería saber por qué is
comporta así.
De hecho, su código equivale a comparar objetos id (es decir, su dirección física). Entonces en vez de tu es una comparación:
>>> b = ''is it the space?''
>>> a = ''is it the space?''
>>> a is b
False
Tu puedes hacer:
>>> id(a) == id(b)
False
Pero, tenga en cuenta que si ayb estuvieran directamente en la comparación, funcionaría.
>>> id(''is it the space?'') == id(''is it the space?'')
True
De hecho, en una expresión hay intercambio entre las mismas cadenas estáticas. Pero, en la escala del programa, solo se comparten elementos similares a palabras (por lo tanto, ni espacios ni signos de puntuación).
No debe confiar en este comportamiento, ya que no está documentado en ningún lugar y es un detalle de la implementación.
El operador is
basa en la función id
, que se guaranteed to be unique among simultaneously existing objects.
Específicamente, id
devuelve la dirección de memoria del objeto. Parece que CPython tiene direcciones de memoria consistentes para cadenas que contienen solo caracteres az y AZ.
Sin embargo, esto parece ser solo el caso cuando la cadena ha sido asignada a una variable:
Aquí, la identificación de "foo" y la identificación de a
son lo mismo. a
se ha establecido en "foo" antes de verificar la identificación.
>>> a = "foo"
>>> id(a)
4322269384
>>> id("foo")
4322269384
Sin embargo, la identificación de "barra" y la identificación de a
son diferentes cuando se verifica la identificación de "barra" antes de establecer a
valor igual a "barra".
>>> id("bar")
4322269224
>>> a = "bar"
>>> id(a)
4322268984
Verificando el ID de "barra" nuevamente después de configurar a
igual" a "barra" se devuelve la misma identificación.
>>> id("bar")
4322268984
Por lo tanto, parece que cPython mantiene direcciones de memoria consistentes para cadenas que contienen solo a-zA-Z cuando esas cadenas están asignadas a una variable. También es completamente posible que esto dependa de la versión: estoy ejecutando Python 2.7.3 en un macbook. Otros pueden obtener resultados completamente diferentes.
Para ampliar un poco la respuesta de Ignacio: El operador es el operador de identidad. Se usa para comparar la identidad del objeto . Si construye dos objetos con los mismos contenidos, generalmente la identidad del objeto no es verdadera. Funciona para algunas cadenas pequeñas porque CPython, la implementación de referencia de Python, almacena los contenidos por separado, haciendo que todos esos objetos hagan referencia al mismo contenido de cadena. Entonces, el operador is
devuelve verdadero para esos.
Sin embargo, este es un detalle de implementación de CPython y generalmente no está garantizado para CPython ni para ninguna otra implementación. Así que usar este hecho es una mala idea, ya que puede romperse cualquier otro día.
Para comparar cadenas, use el operador ==
que compara la igualdad de objetos. Dos objetos de cadena se consideran iguales cuando contienen los mismos caracteres. Así que este es el operador correcto para usar cuando se comparan cadenas, y generalmente is
debe evitar si no se desea explícitamente la identidad del objeto (ejemplo: a is False
).
Si está realmente interesado en los detalles, puede encontrar la implementación de las cadenas de CPython here . Pero otra vez: este es el detalle de la implementación, por lo que nunca debe exigir que esto funcione.
el operador ''is'' compara el objeto real.
c is d
también debería ser falso. Supongo que Python hace algo de optimización y en ese caso, es el mismo objeto.
Advertencia: esta respuesta se trata de los detalles de implementación de un intérprete de Python específico. comparar cadenas con is
== mala idea.
Bueno, al menos para cpython3.4 / 2.7.3, la respuesta es "no, no es el espacio en blanco". No solo el espacio en blanco:
Dos literales de cadena compartirán memoria si son alfanuméricos o residen en el mismo bloque (archivo, función, clase o comando de intérprete único)
Una expresión que se evalúa como una cadena dará como resultado un objeto que es idéntico al creado con un literal de cadena, si y solo si se crea utilizando constantes y operadores binarios / unarios, y la cadena resultante tiene menos de 21 caracteres.
Los personajes únicos son únicos.
Ejemplos
Los literales de cadena alfanuméricos siempre comparten memoria:
>>> x=''aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa''
>>> y=''aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa''
>>> x is y
True
Los literales de cadena no alfanuméricos comparten memoria solo si comparten el bloque sintáctico adjunto:
(Interprete)
>>> x=''`!@#$%^&*() /][=-. >:"?<a''; y=''`!@#$%^&*() /][=-. >:"?<a'';
>>> z=''`!@#$%^&*() /][=-. >:"?<a'';
>>> x is y
True
>>> x is z
False
(archivo)
x=''`!@#$%^&*() /][=-. >:"?<a'';
y=''`!@#$%^&*() /][=-. >:"?<a'';
z=(lambda : ''`!@#$%^&*() /][=-. >:"?<a'')()
print(x is y)
print(x is z)
Salida: True
y False
Para las operaciones binarias simples, el compilador hace una propagación de constante muy simple (ver peephole.c ), pero con cadenas solo lo hace si la cadena resultante es más corta que 21 charcters. Si este es el caso, las reglas mencionadas anteriormente están vigentes:
>>> ''a''*10+''a''*10 is ''a''*20
True
>>> ''a''*21 is ''a''*21
False
>>> ''aaaaaaaaaaaaaaaaaaaaa'' is ''aaaaaaaa'' + ''aaaaaaaaaaaaa''
False
>>> t=2; ''a''*t is ''aa''
False
>>> ''a''.__add__(''a'') is ''aa''
False
>>> x=''a'' ; x+=''a''; x is ''aa''
False
Los personajes únicos siempre comparten memoria, por supuesto:
>>> chr(0x20) is '' ''
True