¿Por qué ‘a’ + ‘bc’ resulta en una cadena diferente (no es) de ‘abc’?

Estaba tratando de averiguar por qué las siguientes “x” y “y” son diferentes.

>>> x = 'a' >>> x += 'bc' >>> x 'abc' >>> y = 'abc' >>> x is y False >>> >>> id(x) 4537718624 >>> id(y) 4537059288 >>> 

¿Por qué los id son diferentes? No estoy buscando información sobre el operador ‘is’. Estoy tratando de averiguar por qué el nuevo objeto creado después de la concatenación es diferente de ‘y’.

is refiere a la identidad, como en la identidad del objeto. == refiere a la igualdad, lo que significa que dos (o el mismo) objeto (s) tienen el mismo valor.

Si cambio el valor de x, el valor de y no cambia, porque no son el mismo objeto, aunque tienen el mismo valor. Si, por otro lado, lo hago.

 x = [1, 2, 3] y = x 

y luego cambiar algo sobre cualquiera de los dos, cambiaré el objeto subyacente al que apuntan xey. Estas son tags (referencias) a objetos subyacentes, no los objetos en sí, y la identidad no es lo mismo que el valor .

Editar:

Imagina que hacemos una clase llamada Persona:

 class Person(object): def __init__(name): self.name = name 

Hay más de un “Joe Smith” en el mundo. Pero no son la misma persona. Esto también es cierto en Python:

 joe1 = Person("Joe Smith") joe2 = Person("Joe Smith") 

Sus identidades son diferentes, porque son objetos diferentes, a pesar de que llevan el mismo valor de nombre. Podríamos crear un operador de comparación en ellos que verifique si los valores de los nombres son equivalentes, por lo que joe1 == joe2 sería cierto, pero joe1 is joe2 nunca será el mismo.

Esta característica de Python es útil cuando necesitas saber si cambiar el estado de un objeto tendrá consecuencias en otros lugares. Por ejemplo, si paso un diccionario a una función, y cambio algo sobre ese diccionario, ha cambiado en todas partes. Esto es particularmente importante porque Python pasa argumentos de función a veces por valor y a veces por referencia, y esto puede resultar incómodo para rastrear errores (especialmente si eres nuevo en Python):

 >>> foo = {'bar': 'baz'} >>> def changeit(z): ... z['spam'] = 'eggs' ... >>> changeit(foo) >>> foo {'bar': 'baz', 'spam': 'eggs'} >>> def changeit2(z): ... if z is foo: ... return "We don't want to mess with this, it affects global state." ... else: ... z['cro'] = 'magnon' ... >>> changeit2(foo) "We don't want to mess with this, it affects global state."