2010-08-10 28 views
8

Xem xét phiên sau. Sự khác biệt được giải thích như thế nào? Tôi nghĩ rằng a += b là một đường cú pháp (và do đó tương đương với) a = a + b. Rõ ràng tôi sai rồi.Xử lý dữ liệu theo tham chiếu hoặc theo giá trị trong python

>>> import numpy as np 
>>> a = np.arange(24.).reshape(4,6) 
>>> print a 
[[ 0. 1. 2. 3. 4. 5.] 
[ 6. 7. 8. 9. 10. 11.] 
[ 12. 13. 14. 15. 16. 17.] 
[ 18. 19. 20. 21. 22. 23.]] 
>>> for line in a: 
...  line += 100 
... 
>>> print a #a has been changed 
[[ 100. 101. 102. 103. 104. 105.] 
[ 106. 107. 108. 109. 110. 111.] 
[ 112. 113. 114. 115. 116. 117.] 
[ 118. 119. 120. 121. 122. 123.]] 
>>> 
>>> for line in a: 
...  line = line + 999 
... 
>>> print a #a hasn't been changed 
[[ 100. 101. 102. 103. 104. 105.] 
[ 106. 107. 108. 109. 110. 111.] 
[ 112. 113. 114. 115. 116. 117.] 
[ 118. 119. 120. 121. 122. 123.]] 

Cảm ơn bạn

Trả lời

15

Sử dụng + kết quả điều hành trong một cuộc gọi đến các phương pháp đặc biệt __add__ mà nên tạo một đối tượng mới và không nên thay đổi bản gốc.

Mặt khác, sử dụng toán tử += dẫn đến một cuộc gọi đến __iadd__ nên sửa đổi đối tượng nếu có thể thay vì tạo đối tượng mới.

__add__

Những phương pháp này được gọi là để thực hiện các phép tính số học nhị phân (+, -, *, //,%, divmod(), pow(), **, < <,> >, &, ^, |). Ví dụ, để đánh giá biểu thức x + y, trong đó x là một thể hiện của một lớp có phương thức __add __(), x .__ add __ (y) được gọi.

__iadd__

Những phương pháp này được gọi là để thực hiện các bài tập số học tăng cường (+ =, - =, * =,/=, // =,% =, = **, < < =,> > =, & =,^=, | =). Những phương pháp này nên cố gắng thực hiện thao tác tại chỗ (sửa đổi tự) và trả lại kết quả (có thể, nhưng không nhất thiết phải là tự).

Tất nhiên, bạn có thể thực hiện __add____iadd__ để có một số hành vi khác nếu muốn, nhưng những gì bạn quan sát là cách chuẩn và được khuyến nghị. Và, có, nó là một chút ngạc nhiên khi lần đầu tiên bạn nhìn thấy nó.

+0

là sự khác biệt này đặc trưng cho python hoặc là nó một đặc điểm chung của '+' '+ vs =' khai thác bằng các ngôn ngữ lập trình? –

+0

@bgbg: Điều này dành riêng cho Python. Trong C#, ví dụ 'a = a + b' gần như tương đương với' a + = b'. –

+0

Giúp nếu bạn xem xét + = là thao tác tăng không cắt ngắn để thêm giá trị. –

7

Bạn không sai, đôi khi a += b thực sự là cú pháp đường cho a = a + b, nhưng đôi khi không, đó là một trong những tính năng khó hiểu hơn của Python - xem this similar question để thảo luận thêm.

Nhà điều hành + gọi phương thức đặc biệt __add__, và += hành cố gắng để cuộc gọi tại chỗ __iadd__ phương pháp đặc biệt, nhưng tôi nghĩ rằng nó có giá trị mở rộng về trường hợp __iadd__ không được định nghĩa.

Nếu toán tử tại chỗ không được xác định, ví dụ cho các loại không thay đổi như chuỗi và số nguyên, thì __add__ được gọi thay thế. Vì vậy, đối với các loại a += b thực sự là cú pháp đường cho a = a + b. Lớp đồ chơi này minh họa điểm:

>>> class A(object): 
...  def __add__(self, other): 
...   print "In __add__ (not __iadd__)" 
...   return A() 
... 
>>> a = A() 
>>> a = a + 1 
In __add__ (not __iadd__) 
>>> a += 1 
In __add__ (not __iadd__) 

Đây là hành vi bạn nên mong đợi từ bất kỳ loại nào không thay đổi.Mặc dù điều này có thể gây nhầm lẫn, thay thế sẽ là không cho phép += về các loại không thể thay đổi sẽ không may như vậy có nghĩa là bạn không thể sử dụng nó trên chuỗi hoặc số nguyên!

Ví dụ khác, điều này dẫn đến một sự khác biệt giữa danh sách và các bộ, cả hai đều hỗ trợ +=, nhưng chỉ liệt kê có thể được chỉnh sửa:

>>> a = (1, 2) 
>>> b = a 
>>> b += (3, 4) # b = b + (3, 4) (creates new tuple, doesn't modify) 
>>> a 
(1, 2) 

>>> a = [1, 2] 
>>> b = a 
>>> b += [3, 4] # calls __iadd___ so modifies b (and so a also) 
>>> a 
[1, 2, 3, 4] 

Tất nhiên cũng áp dụng cho tất cả các khác tại chỗ khai thác, -=, *=, //=, %= vv

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