2009-04-07 99 views
110

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

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 có nghĩa là 'mở rộng'. – hasen

+0

Đối với trường hợp thú vị hơn của '+ =' vs 'extend': http://stackoverflow.com/questions/3653298/concatenating-two-lists-difference-between-and-extend –

Trả lời

153

Đối với trường hợp của bạn, sự khác biệt duy nhất là hiệu suất: nối thêm nhanh gấp hai lần.

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 append sẽ thêm một mục vào danh sách, trong khi += sẽ sao chép tất cả yếu tố của danh sách bên tay phải phía vào danh sách bên trái phía.

Cập nhật: Perf phân tích

So sánh bytecode chúng ta có thể giả định rằng append chất thải phiên bản chu kỳ trong LOAD_ATTR + CALL_FUNCTION, và + = phiên bản - trong BUILD_LIST. Rõ ràng là BUILD_LIST outweighs 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 ta có thể cải thiện hiệu suất thậm chí nhiều hơn bằng cách loại bỏ LOAD_ATTR overhead:

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

+1: Điều này rất thú vị. Dù sao tôi vẫn sử dụng phụ thêm, 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 đã có thể mong đợi nối thêm chậm hơn, vì nó là một cuộc gọi chức năng đảm bảo, trong khi tôi giả sử + = sẽ được tối ưu hóa hơn nữa. – DNS

+0

Cũng không có sự khác biệt về chức năng? Ví dụ: let ** a = [] **, ** b = [4,5,6] **, ở đây nếu bạn thực hiện ** 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] **. – rkioji

+0

chỉ để đặt mọi thứ thẳng: + = mang lại hiệu suất tốt hơn mở rộng hoặc nối thêm miễn là đầu vào của bạn ở định dạng phù hợp. Thời gian cần thiết trong ví dụ hiện tại là việc tạo danh sách ['something']. + = nhanh hơn khoảng 15% – 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ó sự khác biệt giữa append+ (câu hỏi ban đầu được hỏi).

>>> 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ó kết quả tương tự; họ thêm mục vào danh sách, mà không cần tạo danh sách mới. Sử dụng + thêm hai danh sách và tạo danh sách mới.

+0

Có * là * sự khác biệt giữa phụ thêm và + =. – Constantin

+3

Có một thực tế là 'append' thê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 để' mở rộng'). Nhưng anh ta/cô ấy đã biết điều đó, xét xử bằng cách câu hỏi được viết. Có một số khác biệt khác 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 rebinding (giải thích trong câu trả lời của tôi). – bobince

20
some_list2 += ["something"] 

thực sự là

some_list2.extend(["something"]) 

cho một giá trị, không có sự khác biệt. bang Documentation, rằng:

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

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

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

thấy rằng append thêm một yếu tố duy nhất để danh sách, có thể là bất cứ điều gì. +=[] tham gia danh sách.

+2

Bỏ phiếu này bởi vì đây là một sự khác biệt quan trọng giữa hai người. Làm tốt lắm. – sli

3

Ngoài những khía cạnh được mô tả trong các câu trả lời khác, thêm và + [] có hành vi rất khác nhau khi bạn đang cố gắng để xây dựng 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 danh sách1 làm thành phần riêng lẻ. list1.append (['5', '6']) thêm danh sách ['5', '6'] vào danh sách1 làm một phần tử đơn.

27

+ = là bài tập. Khi bạn sử dụng nó, bạn thực sự nói ‘some_list2 = some_list2 + ['something']’. Bài tập liên quan đến rebinding, 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 

Các + = điều hành cũng nên thường tạo ra một đối tượng danh sách mới như danh sách + danh sách thường làm:

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

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

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

Tuy nhiên trong thực tế:

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

Điều này là do các danh sách Python thực hiện __iadd__() để thực hiện một + = augmented assignment-circuit và gọi list.extend() để thay thế. (Đó là một chút của một điều kỳ lạ này: nó thường làm những gì bạn có nghĩa là, nhưng vì lý do khó hiểu.)

Nói chung, nếu bạn đang thêm/mở rộng 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 cái mới), tốt nhất là phải rõ ràng và gắn bó với các phương thức append()/extend().

5

Các thử nghiệm hiệu suất ở đây là không đúng:

  1. Bạn không nên chạy hồ sơ cá nhân chỉ một lần.
  2. Nếu so sánh chắp thêm so với + = [] số lần bạn nên khai báo nối thêm dưới dạng hàm cục bộ.
  3. kết quả thời gian là 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): ứng dụng (i)', 's = []; ứng dụng = s.append') timeit()

.

kiểm tra tốt có thể được tìm thấy ở đây: http://markandclick.com/1/post/2012/01/python-list-append-vs.html

+0

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

1

Các hành vi rebinding đề cập trong câu trả lời khác không thành vấn đề trong một số trường hợp:

>>> 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ì nhiệm vụ tăng cường luôn luôn rebinds, ngay cả khi đối tượng đã được đột biến tại chỗ. Việc khôi phục ở đây xảy ra là a[1] = *mutated list*, không hoạt động đối với bộ dữ liệu.

5

Sự khác biệt là concatenate sẽ san bằng danh sách kết quả, trong khi append sẽ giữ mức nguyên vẹn:

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

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

Sử dụng append, bạn kết thúc với danh sách danh sách:

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

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

>> myList += listA + listB 
>> myList 
[1,2,3,"a","b","c"] 
Các vấn đề liên quan