简体   繁体   中英

What is the difference between LIST.append(1) and LIST = LIST + [1] (Python)

When I execute (I'm using the interactive shell) these statements I get this:

L=[1,2,3]
K=L

L.append(4)

L
[1,2,3,4]
K
[1,2,3,4]

But when I do exactly the same thing replacing L.append(4) with L=L+[4] I get:

L
[1,2,3,4]
K
[1,2,3]

Is this some sort of reference thing? Why does this happen?

Another funny thing I noticed is that L+=[4] acts like .append, which is odd as I thought it would act like L = L + [4].

Clarification to all of this would be greatly appreciated.

Thanks

L.append(4)

This adds an element on to the end of the existing list L .

L += [4]

The += operator invokes the magic __iadd__() method. It turns out list overrides the __iadd__() method and makes it equivalent to extend() which, like append() , adds elements directly onto an existing list.

L = L + [4]

L + [4] generates a new list which is equal to L with 4 added to the end. This new list is then assigned back to L . Because you've created a new list object, K is unchanged by this assignment.

We can use id() to identify when a new object reference is created:

>>> L = [1, 2, 3]
>>> id(L)
152678284
>>> L.append(4)
>>> id(L)
152678284

>>> L = [1, 2, 3]
>>> id(L)
152680524
>>> L = L + [4]
>>> id(L)
152678316

With append you're modifying the list directly. With L=L+[4] , you're making a copy of the original L and adding a new element, then assigning that result back to L and breaking its equivalence to K .

I'm not sure about the behavior of += .

If you are curious about the bytecodes:

>>> def L_app( ):
...     L.append( 4 )
...
>>> def L_add( ):
...     L = L + [ 4 ]
...
>>> def L_add_inplace( ):
...     L += [ 4 ]
...
>>> dis.dis( L_app )
  2           0 LOAD_GLOBAL              0 (L)
              3 LOAD_ATTR                1 (append)
              6 LOAD_CONST               1 (4)
              9 CALL_FUNCTION            1
             12 POP_TOP
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
>>> dis.dis( L_add )
  2           0 LOAD_FAST                0 (L)
              3 LOAD_CONST               1 (4)
              6 BUILD_LIST               1
              9 BINARY_ADD
             10 STORE_FAST               0 (L)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
>>> dis.dis( L_add_inplace )
  2           0 LOAD_FAST                0 (L)
              3 LOAD_CONST               1 (4)
              6 BUILD_LIST               1
              9 INPLACE_ADD
             10 STORE_FAST               0 (L)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE

In your first example K and L variable names refer to the same object, so when you invoke a method mutating that object, changes are obviously seen through both references. In the second example + operator invokes list.__add__ which returns new object (concatenation of two lists) and L name now refers to this new object, while K is intact.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM