The augmented assignment operator += hooks into the datamodel magic method __iadd__ ("in-place addition"). If this method doesn't exist, it falls back to using the regular __add__ method. From the docs:
These methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self). If a specific method is not defined, the augmented assignment falls back to the normal methods.
It happens that int doesn't define int.__iadd__, because it does not make sense to do anything "in-place" on an immutable type.
>>> int.__iadd__
AttributeError: type object 'int' has no attribute '__iadd__'
However, list does implement it, and "extends" the existing list with elements taken from iterating the right hand side:
>>> list.__iadd__
<slot wrapper '__iadd__' of 'list' objects>
So when foo == 0, the augmented assignment foo += 1 does something like this:
foo = foo.__add__(1)  # returns a different integer instance
Whereas when foo == [] the augmented assigmnent foo += [1] does something more like this:
foo = foo.__iadd__([1])  # modifies foo in-place and returns foo again
It follows that foo, bar, and cue are names bound to different integer objects in the first case, but bound to the same list instance in the second case.