Почему "a" + "bc" приводит к другой строке (не-is) из "abc"?

Я пытался понять, почему следующие "x" и "y" отличаются.

>>> x = 'a' 
>>> x += 'bc'
>>> x
'abc'
>>> y = 'abc'
>>> x is y
False
>>>

>>> id(x)
4537718624
>>> id(y)
4537059288
>>>

Почему идентификатор отличается? Я не ищу информацию об операторе 'is'. Я пытаюсь понять, почему новый объект, созданный после конкатенации, отличается от "y".

Ответ 1

is относится к идентичности, как и к идентичности объекта. == означает равенство, означающее, что два (или тот же) объект имеют одинаковое значение.

Если я изменяю значение x, значение y не изменяется, потому что они не являются одним и тем же объектом, хотя они имеют одинаковое значение. Если, с другой стороны, я делаю

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

а затем измените что-то об этом, я буду изменять базовый объект, на который указывают x и y. Это метки (ссылки) на базовые объекты, а не сами объекты, а идентификация - это не то же самое, что значение.

Edit:

Представьте, что мы создаем класс Person:

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

В мире существует более одного "Джо Смита". Но это не тот человек. Это также верно в Python:

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

Их идентификаторы разные, потому что они разные объекты, несмотря на то, что они имеют одно и то же имя. Мы могли бы создать на них оператор сравнения, который проверяет, эквивалентны ли значения имени, поэтому joe1 == joe2 будет true, но joe1 is joe2 никогда не будет прежним.

Эта функция Python полезна, когда вам нужно знать, будет ли изменение состояния объекта иметь последствия в другом месте. Например, если я передаю словарь в функцию и что-то изменил в отношении этого словаря, он повсеместно изменился. Это особенно важно, потому что Python передает аргументы функции иногда по значению, а иногда и по ссылке, и это может привести к неудобности отслеживать ошибки (особенно если вы новичок в 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."