2010-07-09 38 views
46

Từ những gì tôi biết, + op cho danh sách chỉ yêu cầu toán hạng thứ hai có thể lặp lại, mà "ha" rõ ràng là.Nếu x là danh sách, tại sao x + = "ha" làm việc, trong khi x = x + "ha" ném một ngoại lệ?

Trong mã:

>>> x = [] 
>>> x += "ha" 
>>> x 
['h', 'a'] 
>>> x = x + "ha" 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: can only concatenate list (not "str") to list 
+1

Tôi "đồng ý" với câu hỏi của bạn; nó là một đối số tốt chống lại quá tải toán tử cho tôi. – u0b34a0f6ae

+0

Đã xóa câu trả lời của tôi sau khi bạn chỉnh sửa - có vẻ như bạn đang băn khoăn về lý do đằng sau không hỗ trợ + giữa danh sách và một lần lặp - lỗi của tôi. Ngoài việc nói, "Ừ, tại sao không?", Tôi không có câu trả lời. –

+3

đó là lỗi * lớn *. nói chung, bất kỳ ngôn ngữ hoặc thư viện nào xác định các hành vi khác nhau cho các nhà khai thác tương tự sẽ được coi là người dùng thù địch. không ai sane sẽ sử dụng '+' cho chuỗi nối: hoạt động đó không giao hoán! –

Trả lời

33

Sử dụng += với một danh sách giống như gọi extend, không +.

  • Bạn có thể gọi extend có thể lặp lại.
  • Bạn chỉ có thể sử dụng + với một danh sách khác.

Tôi chỉ có thể đoán tại sao quyết định này được đưa ra, nhưng tôi cho rằng đó là vì lý do hiệu suất. Gọi + kết quả trong một đối tượng mới được tạo và tất cả các mục được sao chép, trong khi extend có thể sử dụng dung lượng trống trong đối tượng danh sách hiện có để lưu bản sao trong một số trường hợp.

Một tác dụng phụ khác của quyết định này là nếu bạn viết x += y các tham chiếu khác vào danh sách sẽ thấy thay đổi nhưng nếu bạn sử dụng x = x + y thì chúng sẽ không. Đây được thể hiện dưới đây:

 
>>> x = ['a','b'] 
>>> y = ['c', d'] 
>>> z = x 
>>> x += y 
>>> z 
['a', 'b', 'c', 'd'] 

>>> x = ['a','b'] 
>>> y = ['c', d'] 
>>> z = x 
>>> x = x + y 
>>> z 
['a', 'b'] 

Tài liệu tham khảo

Python source code for list.

Mã nguồn cho +=:

 
static PyObject * 
list_inplace_concat(PyListObject *self, PyObject *other) 
{ 
    PyObject *result; 

    result = listextend(self, other); 
    if (result == NULL) 
     return result; 
    Py_DECREF(result); 
    Py_INCREF(self); 
    return (PyObject *)self; 
} 

Mã nguồn cho +:

 
static PyObject * 
list_concat(PyListObject *a, PyObject *bb) 
{ 
    Py_ssize_t size; 
    Py_ssize_t i; 
    PyObject **src, **dest; 
    PyListObject *np; 
    if (!PyList_Check(bb)) { 
     PyErr_Format(PyExc_TypeError, 
        "can only concatenate list (not \"%.200s\") to list", 
        bb->ob_type->tp_name); 
     return NULL; 
    } 

    // etc ... 
+20

Tôi nghĩ câu hỏi thực sự ở đây là, "tại sao sự không thống nhất đó?" – doublep

+0

Tôi đang trên bờ vực đi -1 về câu trả lời này vì nó không trả lời câu hỏi nào cả (xem nhận xét của @ doublep). –

+5

Tôi không nghĩ rõ ràng rằng câu hỏi này là một phê bình về thiết kế. Bước đầu tiên là phải hiểu sự không thống nhất được thực hiện như thế nào, và đây là tất cả những gì chúng tôi có thể giúp đỡ ở đây. Các câu hỏi lớn hơn mà bạn bình luận hỏi là hoàn toàn nằm ngoài phạm vi của SO, nếu bạn hỏi tôi :) –

8

Bạn đang suy nghĩ về nó về phía sau. Bạn đang hỏi tại sao x = x + 'ha' ném ngoại lệ, cho rằng x += 'ha' hoạt động. Thực sự, câu hỏi là lý do tại sao tất cả các công trình x += 'ha' đều hoạt động.

Mọi người đồng ý (tôi hy vọng) rằng 'abc' + 'ha'[1, 2, 3] + ['h', 'a'] sẽ hoạt động. Và trong những trường hợp này, quá tải += để thực hiện sửa đổi tại chỗ có vẻ hợp lý.

Nhà thiết kế ngôn ngữ quyết định rằng [1, 2, 3] + 'ha' không nên vì bạn đang pha trộn các loại khác nhau. Và điều đó có vẻ hợp lý.

Vì vậy, câu hỏi là tại sao họ quyết định cho phép trộn các loại khác nhau trong trường hợp x += 'ha'. Trong trường hợp này, tôi tưởng tượng có một vài lý do:

  • Đó là một cách viết tắt thuận tiện
  • Rõ ràng những gì xảy ra (bạn nối thêm mỗi mục trong iterable để x)

Nhìn chung , Python cố gắng để cho bạn làm những gì bạn muốn, nhưng ở đâu có sự mơ hồ, nó có xu hướng buộc bạn phải rõ ràng.

+2

một giả thuyết -1: với tôi rõ ràng là 'x + = y' được định nghĩa là' x = x + y' cho bất kỳ 'x' và' y' nào. rõ ràng là bạn đã tránh trả lời câu hỏi. ;) –

+6

Tôi nghĩ rằng điểm ở đây là nó là * không * rõ ràng, do đó câu hỏi. Trong hầu hết các ngôn ngữ lập trình khác mà cả hai '+ =' và '+' được định nghĩa, làm 'x + = y' thường được định nghĩa là chính xác giống như' x = x + y'. Trong thực tế, thông thường một là một bí danh cho người khác. –

+0

Điều hiển nhiên là nếu bạn thử, điều đó sẽ rất rõ ràng. Và nó không phải là, nếu bạn không mong đợi nó để làm việc, bạn sẽ thất vọng khi nó. –

5

Khi xác định toán tử, có hai toán tử "thêm" khác nhau: Một được gọi là __add__, số khác __iadd__. Cái thứ hai là để bổ sung tại chỗ với +=, cái còn lại là toán tử + thông thường. http://docs.python.org/reference/datamodel.html có nhiều thông tin hơn về điều đó.

Các vấn đề liên quan