The difference between the two is that b += 3 is an assignment -- it is assigning a totally new value (the result of addition of your empty list and 3) to b.  b.append(), in contrast, mutates the list referenced by b without reassigning it.
inner() is accessing a variable in its parent's scope (I think this is not technically a closure since the execution of the parent has not completed).  But inner() can only dereference that name, not assign to it, because b is not local to inner() and is not declared as global or nonlocal.
So you can dereference b and mutate the list it refers to, but you cannot assign to it.  When you try to assign to it by starting the line with b += you are saying "treat b like a local".  On a normal b = 3 assignment this would actually complete successfully, creating a local variable like any other.  But in this case, since b has no already assigned value in the local context, dereferencing b in order to perform the addition procedure fails. 
As it happens, you can't simply add an integer to a list in the first place. += is not the same thing as append even setting aside assignment vs. mutation, so even if you weren't reaching out of scope it would fail with a TypeError.  b += [3] is closer to what you mean, although it will still fail due to the variable's scope.