2010-06-04 32 views
10

Một câu hỏi đơn giản, có lẽ, nhưng tôi không thể cụm từ câu truy vấn Google của tôi để tìm câu trả lời ở đây. Tôi đã có thói quen tạo bản sao của đối tượng khi tôi chuyển chúng vào nhà xây dựng đối tượng, như vậy:Python có sao chép giá trị hoặc tham chiếu khi khởi tạo đối tượng không?

... 
def __init__(self, name): 
    self._name = name[:] 
... 

Tuy nhiên, khi tôi chạy các mã kiểm tra sau, nó dường như không cần thiết, đó là Python đang thực hiện bản sao sâu của các giá trị đối tượng khi khởi tạo đối tượng:

>>> class Candy(object): 
...  def __init__(self, flavor): 
...    self.flavor = flavor 
... 
>>> flav = "cherry" 
>>> a = Candy(flav) 
>>> a 
<__main__.Candy object at 0x00CA4670> 
>>> a.flavor 
'cherry' 
>>> flav += ' and grape' 
>>> flav 
'cherry and grape' 
>>> a.flavor 
'cherry' 

Vậy, câu chuyện có thật ở đây là gì? Cảm ơn!

EDIT:

Nhờ @Olivier cho câu trả lời tuyệt vời của mình. Các mã sau đây tài liệu một ví dụ tốt hơn mà Python không sao chép bằng cách tham khảo:

>>> flav = ['a','b'] 
>>> a = Candy(flav) 
>>> a.flavor 
['a', 'b'] 
>>> flav[1] = 'c' 
>>> flav 
['a', 'c'] 
>>> a.flavor 
['a', 'c'] 

Trả lời

13

Đó là bởi vì dây là bất biến.

Nhà điều hành +=, thay vì gây nhầm lẫn, thực sự reassigns biến nó được áp dụng cho, nếu đối tượng là bất di bất dịch:

s = 'a' 
ids = id(s) 
s += 'b' 
ids == id(s) # False, because s was reassigned to a new object 

Vì vậy, trong trường hợp của bạn, ngay từ đầu, cả hai flava.flavor điểm đến đối tượng chuỗi giống nhau:

flav --------\ 
       'cherry' 
a.flavor ----/ 

Nhưng khi bạn viết flav += 'and grape' biến flav được bố trí đến một đối tượng chuỗi mới:

flav --------> 'cherry and grape' 
a.flavor ----> 'cherry' # <-- that string object never changes 

Đó là khó hiểu, bởi vì thông thường, khi bạn gọi một nhà điều hành trên một biến, nó không thay đổi biến. Nhưng chỉ trong trường hợp của một đối tượng bất biến, nó gán lại biến.

Vì vậy, câu trả lời cuối cùng cho câu hỏi của bạn là, có nghĩa là sao chép các đối tượng khi khởi tạo, đặc biệt nếu bạn đang mong đợi một đối tượng có thể thay đổi (thường là trường hợp). Nó là đối tượng không thay đổi, nó sẽ không gây hại cho việc sao chép nó.

+3

Để làm rõ, 'tự.flavor = flavor' không sao chép theo tham chiếu, nhưng vì chuỗi không thay đổi nên đối tượng được tham chiếu không thể thay đổi được. Do đó, 'flav + = 'và grape' thực sự tạo ra một đối tượng chuỗi mới và làm cho nó tham chiếu' flav'. – taleinat

+0

@taleinat: cảm ơn, tôi đã cập nhật câu trả lời, hy vọng nó không gây nhầm lẫn. –

+0

Cảm ơn các bạn đã trả lời. Tôi đoán sau đó, tôi vẫn còn tự hỏi nếu sao chép các đối tượng khi instantiation là một ý tưởng tốt, vì tôi không nhìn thấy nhiều nơi mà nó được thực hiện. Có đề xuất nào không? – daveslab

1

nó dường như không cần thiết

xuất hiện? Câu hỏi của bạn là hoàn toàn về thiết kế và ý nghĩa. Đây không phải là một sở thích hay câu hỏi về thói quen.

Hợp đồng lớp học có bao gồm khả năng sửa đổi đối số có thể thay đổi không? Nếu có, đừng tạo một bản sao.

Hợp đồng lớp có khẳng định rằng đối số có thể thay đổi sẽ không bị sửa đổi không? Nếu vậy, bạn PHẢI làm một bản sao.

Câu hỏi của bạn được trả lời hoàn toàn theo định nghĩa hợp đồng cho lớp học.

+0

Tôi thấy khu vực của sự nhầm lẫn của bạn. Tôi nên có một câu ở trên đầu nói rằng mục tiêu của tôi là đảm bảo rằng các biến được chuyển đến '__init__' được sao chép theo giá trị, không phải bằng cách tham chiếu đến đối tượng. Những gì tôi có nghĩa là bởi 'Nó dường như không cần thiết' là có vẻ như tôi không cần phải sử dụng phương pháp sao chép của tôi bởi vì Python đã làm nó anyway. Tôi đã sai. – daveslab

+1

@daveslab: Không bình luận. Sửa câu hỏi. Vui lòng ** cập nhật ** câu hỏi để nêu rõ mục tiêu của bạn thực sự là gì. Những người khác đọc những câu hỏi này cố gắng học Python và thiết kế chương trình tốt. Vui lòng sửa câu hỏi để hoàn toàn rõ ràng. –

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