2009-09-08 40 views
53

Tại sao là "hello" is "hello" == True bằng Python?Python: Tại sao ("hello" là "hello") đánh giá là True?

Tôi đọc phần sau đây here:

Nếu hai xâu đều bình đẳng, họ đã được đưa vào cùng một vị trí bộ nhớ . Một chuỗi là một thực thể bất biến. Không làm hại được .

Vì vậy, có một và chỉ một nơi trong bộ nhớ cho mọi chuỗi Python? Âm thanh khá lạ. Những gì đang xảy ra ở đây?

+0

Xem tại đây để thay thế: http: //pyref.infogami.com/intern – bzlm

+0

Ngoài ra, hãy xem hàm 'id' để kiểm tra các vị trí bộ nhớ:' print id ("hello") ' – Blixt

+0

bzlm, liên kết pyref.infogami.com/intern đã chết, nhưng archive.org có một sao chép tại đây:
http://web.archive.org/web/20090429040354/http://pyref.infogami.com/intern
Tuy nhiên, mặc dù điều này thường đúng, KHÔNG PHẢI là đúng, vì @bobince đã chứng minh rất ở dưới. –

Trả lời

80

Python (như Java, C, C++, .NET) sử dụng chuỗi gộp/interning. Thông dịch viên nhận ra rằng "hello" giống như "hello", vì vậy nó tối ưu hóa và sử dụng cùng một vị trí trong bộ nhớ.

Một goodie: "địa ngục" + "o" là "hello" ==> Đúng

+23

Ngay cả C/C++ thường làm điều này; "foo" == "foo" thường đúng trong C. Trong cả C và Python, đây là chi tiết triển khai; Tôi không nghĩ rằng bất cứ điều gì trong Python * yêu cầu * rằng các thông dịch viên làm điều này, và trong C/C++ đây là một tối ưu hóa mà không phải tất cả các trình biên dịch làm và nó có thể được vô hiệu hóa. (Ngược lại, thuộc tính này là * luôn luôn * đúng trong Lua; tất cả các chuỗi được thực hiện.) –

+2

@Glenn, bạn đúng và tôi rất vui vì ai đó đã đề cập. Chắc chắn không ai nên tin rằng điều này là đúng. – Triptych

+0

Nó là một thông dịch viên hoặc trình biên dịch cho các ngôn ngữ như c/C++ công việc cụ thể để làm điều này tối ưu hóa bằng cách làm cho thời gian biên dịch xác định chuỗi giống nhau. – andy

1

Tại sao nó lạ. Nếu chuỗi là bất biến, nó có ý nghĩa rất nhiều để chỉ lưu trữ nó một lần. .NET có cùng một hành vi.

+1

Làm thế nào để thực hiện chuỗi liên quan đến bất biến? Nhiều thứ trong cả Python và ".NET" đều không thay đổi mà không bị interned. – bzlm

+1

Bởi vì nếu nó có thể cho một chuỗi chữ để thay đổi trong bộ nhớ, nó không thể được chia sẻ (hoặc "interned"). – harto

+0

Đúng, nhưng với thực tế, đối tượng là bất biến cho phép chia sẻ an toàn tham chiếu đến cá thể. –

2

Các thông dịch Python/biên dịch phân tích các xâu, ví dụ: danh sách trích dẫn của các nhân vật. Khi nó thực hiện điều này, nó có thể phát hiện "Tôi đã nhìn thấy chuỗi này trước" và sử dụng cùng biểu diễn như lần trước. Nó có thể làm điều này vì nó biết rằng các chuỗi được định nghĩa theo cách này không thể thay đổi được.

14

Chuỗi chữ có thể được nhóm lại dựa trên mã băm của chúng hoặc tương tự. Hai trong số các chuỗi chữ giống nhau sẽ được lưu trữ trong cùng một bộ nhớ và bất kỳ tham chiếu nào đều đề cập đến điều đó.

Memory  Code 
------- 
|   myLine = "hello" 
|  /
|hello < 
|  \ 
|   myLine = "hello" 
------- 
+2

Đây chính xác là câu trả lời được chấp nhận cho biết ... – Martin

+2

Upvote để chống lại những kẻ xấu xa – Martin

+4

+1: câu trả lời được chấp nhận không có nghệ thuật ASCII đẹp :-) – kriss

6

Toán tử is trả về true nếu cả hai đối số là cùng một đối tượng. Kết quả của bạn là kết quả của việc này và bit được trích dẫn.

Trong trường hợp các chuỗi ký tự, chúng được thực tập, nghĩa là chúng được so sánh với các chuỗi đã biết. Nếu một chuỗi giống hệt nhau đã được biết, chữ có giá trị đó, thay vì một giá trị thay thế. Do đó, chúng trở thành cùng một đối tượng và biểu thức là đúng.

+0

Chúng "trở thành cùng một đối tượng"? Nếu bạn sửa đổi một, cái kia không bị sửa đổi. – endolith

+3

@endolith: Đối tượng được đề cập là chuỗi nội bộ, không phải biến được gán cho chuỗi đó. Không có cách nào, trong python, để sửa đổi một chuỗi. – SingleNegationElimination

57

Vì vậy, có một và chỉ một nơi trong bộ nhớ cho mọi chuỗi Python?

Không, chỉ những người thông dịch mới quyết định tối ưu hóa, quyết định dựa trên chính sách không thuộc đặc điểm ngôn ngữ và có thể thay đổi trong các phiên bản CPython khác nhau.

ví dụ: trên tôi cài đặt (2.6.2 Linux):

>>> 'X'*10 is 'X'*10 
True 
>>> 'X'*30 is 'X'*30 
False 

tương tự cho ints:

>>> 2**8 is 2**8 
True 
>>> 2**9 is 2**9 
False 

Vì vậy, không dựa vào 'string' là 'chuỗi': thậm chí chỉ cần nhìn vào việc thực hiện C nó không an toàn.

+11

Vì vậy, bạn nên luôn sử dụng '==' để so sánh chuỗi bình đẳng. – SingleNegationElimination

+0

Thông dịch viên lưu trữ các số nguyên nhỏ (tối đa 256) bằng Python. Vì vậy, 'a = 50; b = 50; a là b' là True, 'a = 500; b = 500; a là b' là Sai. –

0

Tôi nghĩ nếu có hai biến (không chỉ là chuỗi) chứa cùng một giá trị, giá trị sẽ chỉ được lưu trữ một lần không hai lần và cả hai biến sẽ trỏ đến cùng một vị trí. Điều này tiết kiệm bộ nhớ.

+0

Không đúng! Nó chỉ liên quan đến chuỗi và số nguyên nhỏ. Ví dụ: khi bạn tạo bản sao của danh sách hoặc từ điển, mặc dù chúng có cùng giá trị (== bình đẳng), chúng không phải là cùng một đối tượng ("là" bình đẳng). Đó là lý do tại sao bạn có thể thay đổi bản sao của danh sách vì bản gốc vẫn không thay đổi (hoặc ngược lại). Lời giải thích tuyệt vời được cung cấp trong chương Động Typing của Học Python bởi O'reilly – fanny