Trong Python, sự khác biệt giữa “.append ()” và “+ = []” là gì?


122

Sự khác biệt giữa:

some_list1 = []
some_list1.append("something")

some_list2 = []
some_list2 += ["something"]

3
nối thêm nếu cho một mục duy nhất. có thể bạn muốn nói extend.
hasen

Đối với trường hợp thú vị hơn của +=vs extend: stackoverflow.com/questions/3653298/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Câu trả lời:


161

Đối với trường hợp của bạn, điểm khác biệt duy nhất là hiệu suất: append nhanh hơn gấp đôi.

Python 3.0 (r30:67507, Dec  3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.20177424499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.41192320500000079

Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.23079359499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.44208112500000141

Trong trường hợp chung, appendsẽ thêm một mục vào danh sách, trong khi +=sẽ sao chép tất cả các phần tử của danh sách bên phải vào danh sách bên trái.

Cập nhật: phân tích hiệu suất

So sánh các mã byte, chúng ta có thể giả định rằng appendphiên bản lãng phí chu kỳ trong LOAD_ATTR+ CALL_FUNCTIONvà + = phiên bản - in BUILD_LIST. Rõ ràng là BUILD_LISTvượt trội hơn LOAD_ATTR+ CALL_FUNCTION.

>>> import dis
>>> dis.dis(compile("s = []; s.append('spam')", '', 'exec'))
  1           0 BUILD_LIST               0
              3 STORE_NAME               0 (s)
              6 LOAD_NAME                0 (s)
              9 LOAD_ATTR                1 (append)
             12 LOAD_CONST               0 ('spam')
             15 CALL_FUNCTION            1
             18 POP_TOP
             19 LOAD_CONST               1 (None)
             22 RETURN_VALUE
>>> dis.dis(compile("s = []; s += ['spam']", '', 'exec'))
  1           0 BUILD_LIST               0
              3 STORE_NAME               0 (s)
              6 LOAD_NAME                0 (s)
              9 LOAD_CONST               0 ('spam')
             12 BUILD_LIST               1
             15 INPLACE_ADD
             16 STORE_NAME               0 (s)
             19 LOAD_CONST               1 (None)
             22 RETURN_VALUE

Chúng tôi có thể cải thiện hiệu suất nhiều hơn nữa bằng cách loại bỏ LOAD_ATTRchi phí:

>>> timeit.Timer('a("something")', 's = []; a = s.append').timeit()
0.15924410999923566

12
+1: Điều này rất thú vị. Tôi vẫn sử dụng append vì nó dẫn đến mã rõ ràng hơn. Nhưng tôi không nhận ra có sự khác biệt về hiệu suất. Nếu bất cứ điều gì, tôi sẽ mong đợi phần nối thêm chậm hơn, vì đó là một lệnh gọi hàm được đảm bảo, trong khi tôi cho rằng + = sẽ được tối ưu hóa hơn nữa.
DNS

2
Không phải cũng có một sự khác biệt về chức năng? Ví dụ: let a = [] , b = [4,5,6] , ở đây nếu bạn làm c = a.append (b) thì c sẽ là danh sách danh sách [[4,5,6]] trong khi c + = b ; sẽ dẫn đến một danh sách đơn giản c = [4,5,6] .
rph

chỉ để thiết lập mọi thứ thẳng thắn: + = mang lại hiệu suất tốt hơn so với mở rộng hoặc nối thêm miễn là đầu vào của bạn ở đúng định dạng. Điều mất thời gian trong ví dụ hiện tại là việc tạo danh sách ['something']. + = nhanh hơn khoảng 15%
Joe

@Joe Nếu bạn đang so sánh append vs +=, thì bạn phải bao gồm việc tạo danh sách như một phần của phép đo. Nếu không, nó sẽ là một câu hỏi khác ( extendvs +=).
jamesdlin

@jamesdlin vâng! Nhưng rất dễ bị nhầm trừ khi bạn đã biết điều này. Một chút chính xác bổ sung không bao giờ làm tổn thương bất cứ ai, phải không?
Joe

48

Trong ví dụ bạn đã đưa ra, không có sự khác biệt, về đầu ra, giữa append+=. Nhưng có một sự khác biệt giữa append+(mà câu hỏi ban đầu được hỏi về).

>>> a = []
>>> id(a)
11814312
>>> a.append("hello")
>>> id(a)
11814312

>>> b = []
>>> id(b)
11828720
>>> c = b + ["hello"]
>>> id(c)
11833752
>>> b += ["hello"]
>>> id(b)
11828720

Như bạn thấy, append+=có cùng một kết quả; họ thêm mục đó vào danh sách mà không tạo danh sách mới. Việc sử dụng +sẽ thêm hai danh sách và tạo ra một danh sách mới.


sự khác biệt giữa append và + =.
Constantin

3
Có một thực tế là appendthêm một mục vào danh sách, trong khi + = thêm nhiều như có trong danh sách khác (tức là bí danh cho extend). Nhưng anh ấy / cô ấy biết điều đó rồi, đánh giá theo cách viết câu hỏi. Có một số khác biệt khác mà tôi đang thiếu?
DNS

1
Có một sự khác biệt bởi vì một bài tập tăng cường giới thiệu việc kết lại (giải thích trong câu trả lời của tôi).
bobince

42
>>> a=[]
>>> a.append([1,2])
>>> a
[[1, 2]]
>>> a=[]
>>> a+=[1,2]
>>> a
[1, 2]

Hãy xem rằng append thêm một phần tử vào danh sách, có thể là bất cứ thứ gì. +=[]tham gia danh sách.


2
Bỏ phiếu vì đây là điểm khác biệt quan trọng giữa hai loại. Làm tốt lắm.

31

+ = là một phép gán. Khi bạn sử dụng nó, bạn thực sự đang nói 'some_list2 = some_list2 + [' something ']'. Nhiệm vụ liên quan đến việc đóng lại, vì vậy:

l= []

def a1(x):
    l.append(x) # works

def a2(x):
    l= l+[x] # assign to l, makes l local
             # so attempt to read l for addition gives UnboundLocalError

def a3(x):
    l+= [x]  # fails for the same reason

Toán tử + = cũng thường tạo một đối tượng danh sách mới như list + list thường làm:

>>> l1= []
>>> l2= l1

>>> l1.append('x')
>>> l1 is l2
True

>>> l1= l1+['x']
>>> l1 is l2
False

Tuy nhiên trên thực tế:

>>> l2= l1
>>> l1+= ['x']
>>> l1 is l2
True

Điều này là do các danh sách Python triển khai __iadd __ () để tạo ngắn mạch + = tăng cường gán và gọi list.extend () thay thế. (Nó hơi kỳ lạ ở điều này: nó thường làm theo ý bạn, nhưng vì những lý do khó hiểu.)

Nói chung, nếu bạn đang thêm / mở rộng một danh sách hiện có và bạn muốn giữ tham chiếu đến cùng một danh sách (thay vì tạo một danh sách mới), tốt nhất nên rõ ràng và gắn bó với append () / expand () các phương pháp.


21
 some_list2 += ["something"]

thực sự là

 some_list2.extend(["something"])

cho một giá trị, không có sự khác biệt. Tài liệu nói rằng:

s.append(x) giống s[len(s):len(s)] = [x]
s.extend(x) nhưs[len(s):len(s)] = x

Vì vậy, rõ ràng s.append(x)là giống nhưs.extend([x])


s.append có một kiểu tùy ý và thêm nó vào danh sách; Đó là một phần phụ thực sự. s.extend nhận một có thể lặp lại (thường là một danh sách) và hợp nhất có thể lặp lại thành s, sửa đổi địa chỉ bộ nhớ của s. Chúng không giống nhau.
W4t3randWind

9

Sự khác biệt là nối sẽ làm phẳng danh sách kết quả, trong khi nối thêm sẽ giữ nguyên các cấp:

Vì vậy, ví dụ với:

myList = [ ]
listA = [1,2,3]
listB = ["a","b","c"]

Sử dụng append, bạn sẽ có một danh sách các danh sách:

>> myList.append(listA)
>> myList.append(listB)
>> myList
[[1,2,3],['a',b','c']]

Thay vào đó, sử dụng nối, bạn sẽ có một danh sách phẳng:

>> myList += listA + listB
>> myList
[1,2,3,"a","b","c"]

5

Các bài kiểm tra hiệu suất ở đây không đúng:

  1. Bạn không nên chạy hồ sơ chỉ một lần.
  2. Nếu so sánh append với + = [] số lần bạn nên khai báo append là một hàm cục bộ.
  3. kết quả thời gian khác nhau trên các phiên bản python khác nhau: 64 và 32 bit

ví dụ

timeit.Timer ('for i in xrange (100): app (i)', 's = []; app = s.append'). timeit ()

các bài kiểm tra hay có thể tham khảo tại đây: http://markandclick.com/1/post/2012/01/python-list-append-vs.html


vẫn sử dụng các kiểm tra + = trong trang đó += [one_var]. Nếu chúng ta bỏ qua việc tạo danh sách, + = sẽ trở thành tùy chọn nhanh nhất.
Joe

3

Ngoài các khía cạnh được mô tả trong các câu trả lời khác, append và + [] có các hành vi rất khác nhau khi bạn đang cố gắng tạo một danh sách các danh sách.

>>> list1=[[1,2],[3,4]]
>>> list2=[5,6]
>>> list3=list1+list2
>>> list3
[[1, 2], [3, 4], 5, 6]
>>> list1.append(list2)
>>> list1
[[1, 2], [3, 4], [5, 6]]

list1 + ['5', '6'] thêm '5' và '6' vào list1 dưới dạng các phần tử riêng lẻ. list1.append (['5', '6']) thêm danh sách ['5', '6'] vào list1 dưới dạng một phần tử duy nhất.


2

Hành vi liên kết được đề cập trong các câu trả lời khác thực sự quan trọng trong một số trường hợp nhất định:

>>> a = ([],[])
>>> a[0].append(1)
>>> a
([1], [])
>>> a[1] += [1]
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Đó là bởi vì phép gán tăng cường luôn liên kết lại, ngay cả khi đối tượng được thay đổi tại chỗ. Sự ràng buộc ở đây xảy ra a[1] = *mutated list*, không hoạt động đối với các bộ giá trị.


0

hãy lấy một ví dụ trước

list1=[1,2,3,4]
list2=list1     (that means they points to same object)

if we do 
list1=list1+[5]    it will create a new object of list
print(list1)       output [1,2,3,4,5] 
print(list2)       output [1,2,3,4]

but if we append  then 
list1.append(5)     no new object of list created
print(list1)       output [1,2,3,4,5] 
print(list2)       output [1,2,3,4,5]

extend(list) also do the same work as append it just append a list instead of a 
single variable 

0

Phương thức append () thêm một mục vào danh sách hiện có

some_list1 = []
some_list1.append("something")

Vì vậy, ở đây some_list1 sẽ được sửa đổi.

Đã cập nhật:

Trong khi việc sử dụng + để kết hợp các phần tử của danh sách (nhiều hơn một phần tử) trong danh sách hiện có tương tự như phần mở rộng (được sửa bởi Flux ).

some_list2 = []
some_list2 += ["something"]

Vì vậy, ở đây some_list2 và ["something"] là hai danh sách được kết hợp.


1
Cái này sai. +=không trả về một danh sách mới. Câu hỏi thường gặp về lập trình cho biết: "... đối với danh sách, __iadd__tương đương với việc gọi extendvào danh sách và trả về danh sách. Đó là lý do tại sao chúng tôi nói rằng đối với danh sách, +=là" viết tắt "cho list.extend". Bạn cũng có thể tự mình thấy điều này trong mã nguồn CPython: github.com/python/cpython/blob/v3.8.2/Objects/…
Flux

0

"+" không thay đổi danh sách

.append () thay đổi danh sách cũ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.