Причины две.
1. Списки - мутабельны, те меняется содержание
2. Использование составного присваивания, которая в отличии от простого присваивания на самом деле пытается вызвать метод .__iadd__(),
Во втором случае будет a.__iadd__(a), таким образом мы в мутабельный обект с помощью метода добавили новые данные.
К примеру a.append(111) тоже изменит оригинал.
Таким образом, используется та же переменная(тот же id в случае с +=)
def appended1(с):
print(f"Айди внутри функции1 перед операцией: {id(с)}")
с *= 2
print(f"Айди внутри функции1 после операциии: {id(с)}")
return
def appended2(d):
print(f"Айди внутри функции1 перед операцией: {id(d)}")
d = d*2
print(f"Айди внутри функции1 после операциии: {id(d)}")
return
a = 2
print(f"Айди вне функции1 перед операцией: {id(a)}")
#Айди переменной внутри функции после операции другой
appended1(a)
print(a)
print(f"Айди вне функции1 после операции: {id(a)}\n")
b = 2
print(f"Айди вне функции2 перед операцией: {id(b)}")
#Айди переменной внутри функции после операции другой
appended2(b)
print(b)
print(f"Айди вне функции2 после операции: {id(b)}\n\n")
list_a = [1,2]
print(f"Айди списка вне функции1 перед операцией: {id(list_a)}")
#Все айдишники будут равны и до и после и вне и внутри функции
appended1(list_a)
print(list_a)
print(f"Айди списка вне функции1 после операции: {id(list_a)}\n")
list_b = [1,2]
print(f"Айди списка вне функции2 перед операцией: {id(list_b)}")
#Айди переменной внутри функции после операции другой
appended2(list_b)
print(list_b)
print(f"Айди списка вне функции1 после операции: {id(list_b)}")