Điều này phụ thuộc hoàn toàn vào đối tượng i.
+=gọi __iadd__phương thức (nếu nó tồn tại - quay trở lại __add__nếu nó không tồn tại) trong khi +gọi __add__phương thức 1 hoặc __radd__phương thức trong một vài trường hợp 2 .
Từ phối cảnh API, __iadd__được cho là được sử dụng để sửa đổi các đối tượng có thể thay đổi tại chỗ (trả lại đối tượng đã bị thay đổi) trong khi __add__sẽ trả về một thể hiện mới của một cái gì đó. Đối với các đối tượng không thay đổi , cả hai phương thức đều trả về một thể hiện mới, nhưng __iadd__sẽ đặt thể hiện mới vào không gian tên hiện tại với cùng tên mà thể hiện cũ có. Đây là lý do tại sao
i = 1
i += 1
dường như tăng lên i. Trong thực tế, bạn nhận được một số nguyên mới và gán nó "trên đầu trang" i- mất một tham chiếu đến số nguyên cũ. Trong trường hợp này, i += 1hoàn toàn giống như i = i + 1. Nhưng, với hầu hết các đối tượng có thể thay đổi, đó là một câu chuyện khác:
Như một ví dụ cụ thể:
a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a #[1, 2, 3, 1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
so với:
a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
thông báo như thế nào trong ví dụ đầu tiên, kể từ bvà atham khảo cùng một đối tượng, khi tôi sử dụng +=trên b, nó thực sự thay đổi b(và anhìn thấy sự thay đổi đó quá - Sau khi tất cả, nó tham khảo danh sách giống nhau). Tuy nhiên, trong trường hợp thứ hai, khi tôi thực hiện b = b + [1, 2, 3], điều này sẽ đưa danh sách btham chiếu và nối nó với một danh sách mới [1, 2, 3]. Sau đó, nó lưu trữ danh sách được nối trong không gian tên hiện tại dưới dạng b- Không liên quan bđến dòng trước đó là gì .
1 Trong biểu thức x + y, nếu x.__add__không thực hiện hoặc nếu x.__add__(y)lợi nhuận NotImplemented và xvà ycó các loại khác nhau , sau đó x + ycố gắng để gọi y.__radd__(x). Vì vậy, trong trường hợp bạn có
foo_instance += bar_instance
nếu Fookhông thực hiện __add__hoặc __iadd__sau đó kết quả ở đây giống như
foo_instance = bar_instance.__radd__(bar_instance, foo_instance)
2 Trong biểu thức foo_instance + bar_instance, bar_instance.__radd__sẽ được thử trước foo_instance.__add__ nếu loại bar_instancelà một lớp con của loại foo_instance(ví dụ issubclass(Bar, Foo)). Các hợp lý cho điều này là bởi vì Barlà trong một ý nghĩa một "cấp cao" đối tượng hơn Foonên Barsẽ nhận được tùy chọn của trọng Foohành vi 's.
+=hành động nhưextend()trong trường hợp danh sách.