2012-07-23 25 views
8

Tôi đã tìm kiếm các câu hỏi về tràn web và ngăn xếp nhưng không thể tìm thấy câu trả lời cho câu hỏi này. Quan sát mà tôi đã thực hiện là trong Python 2.7.3, nếu bạn chỉ định hai biến cùng một chuỗi ký tự, ví dụ:Trong trường hợp nào các chuỗi bằng nhau chia sẻ cùng một tham chiếu?

>>> a = 'a' 
>>> b = 'a' 
>>> c = ' ' 
>>> d = ' ' 

Sau đó, các biến sẽ chia sẻ các tài liệu tham khảo giống nhau:

>>> a is b 
True 
>>> c is d 
True 

Điều này cũng đúng đối với một số chuỗi dài hơn:

>>> a = 'abc' 
>>> b = 'abc' 
>>> a is b 
True 
>>> ' ' is ' ' 
True 
>>> ' ' * 1 is ' ' * 1 
True 

Tuy nhiên, có rất nhiều trường hợp các tài liệu tham khảo is (unexpectantly) not shared:

>>> a = 'a c' 
>>> b = 'a c' 
>>> a is b 
False 
>>> c = ' ' 
>>> d = ' ' 
>>> c is d 
False 
>>> ' ' * 2 is ' ' * 2 
False 

Ai đó có thể giải thích lý do cho điều này?

Tôi nghi ngờ có thể có sự đơn giản hóa/thay thế được thực hiện bởi thông dịch viên và/hoặc một số cơ chế lưu bộ nhớ đệm sử dụng thực tế là các chuỗi python không thay đổi được trong một số trường hợp đặc biệt. Tôi đã thử tạo các bản sao sâu của các chuỗi bằng cách sử dụng hàm tạo str và hàm copy.deepcopy nhưng các chuỗi vẫn không nhất quán chia sẻ các tham chiếu.

Lý do tôi gặp vấn đề với điều này là vì tôi kiểm tra sự bất bình đẳng của các tham chiếu đến chuỗi trong một số bài kiểm tra đơn vị tôi đang viết cho các phương pháp nhân bản của các lớp python kiểu mới.

Trả lời

8

Chi tiết khi chuỗi được lưu trong bộ nhớ cache và sử dụng lại là phụ thuộc vào triển khai thực hiện, có thể thay đổi từ phiên bản Python sang phiên bản Python và không thể dựa vào. Nếu bạn muốn kiểm tra chuỗi cho sự bình đẳng, hãy sử dụng ==, không phải is.

Trong CPython (thực thi Python phổ biến nhất), chuỗi ký tự xảy ra trong mã nguồn luôn được tập trung, vì vậy nếu cùng một chuỗi ký tự xảy ra hai lần trong mã nguồn, chúng sẽ kết thúc bằng một chuỗi vật. Trong Python 2.x, bạn cũng có thể gọi hàm dựng sẵn intern() để buộc một chuỗi cụ thể được thực tập, nhưng bạn thực sự không nên làm như vậy.

Chỉnh sửa liên quan đến bạn mục đích thực sự của việc kiểm tra xem thuộc tính có được chia sẻ không đúng cách giữa các trường hợp hay không: Loại séc này chỉ hữu ích cho các đối tượng có thể thay đổi. Đối với các thuộc tính của kiểu bất biến, không có sự khác biệt ngữ nghĩa giữa các đối tượng được chia sẻ và không được chia sẻ. Bạn có thể loại trừ các loại không thể sửa đổi khỏi các thử nghiệm của mình bằng cách sử dụng

Immutable = basestring, tuple, numbers.Number, frozenset 
# ... 
if not isinstance(x, Immutable): # Exclude types known to be immutable 

Lưu ý rằng điều này cũng sẽ loại trừ bộ dữ liệu chứa đối tượng có thể thay đổi. Nếu bạn muốn thử nghiệm chúng, bạn sẽ cần phải đệ quy xuống các bộ dữ liệu.

+0

Cảm ơn bạn đã trả lời của bạn, có vẻ như bạn là chính xác về điều đó literals chuỗi trong mã nguồn luôn thực tập nội trú (chuỗi mà không phải là các chữ không có tài sản này). Do đó, các ví dụ của tôi chỉ hợp lệ khi viết trong trình thông dịch tương tác python. Tôi đang sử dụng CPython và câu trả lời của bạn xác nhận một số nghi ngờ của tôi. Tôi đồng ý rằng toán tử == nên được sử dụng để kiểm tra chuỗi cho sự bình đẳng. Có cách nào thanh lịch để kiểm tra nơi một thuộc tính được khởi tạo hay tôi nên tránh loại thử nghiệm này? – EriF89

+0

@ EriF89: Kiểm tra "nơi một thuộc tính được khởi tạo" nghĩa là gì? Và nó quan trọng như thế nào? –

+0

Vì tôi đang viết các bài kiểm tra để đảm bảo rằng các tham chiếu thuộc tính không được chia sẻ không đúng giữa các đối tượng nhân bản, tôi muốn một cách chung để kiểm tra những thay đổi trong một trong các đối tượng không bị rò rỉ. Tôi nghĩ toán tử is sẽ làm điều này nhưng vì các tham chiếu được chia sẻ, tôi đoán tôi phải gán các giá trị mới cho các thuộc tính của một trong các đối tượng, và kiểm tra xem chúng có thay đổi trong các đối tượng khác hay không. – EriF89

4

Tôi nghĩ rằng đó là một điều thực hiện và tối ưu hóa. Nếu chuỗi ngắn, chúng có thể (và thường là?) "Được chia sẻ", nhưng bạn không thể phụ thuộc vào điều đó. Khi bạn có chuỗi dài hơn, bạn có thể thấy rằng chúng không giống nhau.

In [2]: s1 = 'abc' 
In [3]: s2 = 'abc' 

In [4]: s1 is s2 
Out[4]: True 

chuỗi dài hơn

In [5]: s1 = 'abc this is much longer' 
In [6]: s2 = 'abc this is much longer' 

In [7]: s1 is s2 
Out[7]: False 

sử dụng == để so sánh chuỗi (và không các nhà điều hành is).

-

OP của quan sát/giả thuyết (trong các ý kiến ​​dưới đây) rằng đây có thể là do số lượng thẻ dường như được hỗ trợ bởi những điều sau đây:

In [12]: s1 = 'a b c' 
In [13]: s2 = 'a b c' 

In [14]: s1 is s2 
Out[14]: False 

nếu so với ban đầu ví dụ về abc ở trên.

+0

Đối với tôi, nó có vẻ như số lượng thẻ (chuỗi chữ cái và số phân cách bằng dây hoặc biểu tượng khác) trong các vấn đề chuỗi: Trong [1] s1 = 'abcthisismuchlonger' Trong [2] s2 = 'abcthisismuchlonger' Trong [3] s1 là s2 Ra [3] Đúng Nếu có nhiều hơn một mã thông báo, chuỗi đó không được chia sẻ. – EriF89

+0

@ EriF89 Có thể, tôi chưa bao giờ thực sự nhìn vào chi tiết về cách thực hiện, tôi chỉ cố gắng nhớ sử dụng '==' khi so sánh chuỗi và không phụ thuộc vào lưu trữ giữa các chuỗi "giống hệt" được chia sẻ. Giả thuyết của bạn về việc làm thế nào điều này được quyết định có ý nghĩa mặc dù, tôi chỉ cố gắng với ''a b c'' và nó xuất hiện như' Sai'. – Levon

5

Trong CPython, dưới dạng chi tiết triển khai the empty string is shared, cũng như các chuỗi ký tự đơn có điểm mã nằm trong dải Latinh-1. Bạn nên không phụ thuộc vào điều này, vì có thể bỏ qua tính năng này.

Bạn có thể yêu cầu một chuỗi là thực tập sử dụng sys.intern; điều này sẽ tự động diễn ra trong một số trường hợp:

Thông thường, các tên được sử dụng trong các chương trình Python sẽ tự động được lưu trữ và các từ điển được sử dụng để giữ khóa.

sys.intern được tiếp xúc để bạn có thể sử dụng nó để thực hiện:

interning chuỗi rất hữu ích để đạt được một chút hiệu suất trên tra cứu từ điển - nếu các phím trong một từ điển được thực tập nội trú (sau khi hồ sơ!) , và khóa tra cứu được tập trung, các so sánh chính (sau khi băm) có thể được thực hiện bằng một con trỏ so sánh thay vì so sánh chuỗi.

Lưu ý rằng intern là một dựng sẵn trong Python 2.

+1

+1 cho liên kết mã nguồn có liên quan. Thú vị, mặc dù các chi tiết về chuỗi nội bộ để tối ưu hóa tra cứu từ điển không liên quan đến tôi vào lúc này. – EriF89

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