2010-05-18 31 views
56

Hãy xem xét mã này:Tại sao từ khóa "là" có hành vi khác khi có một dấu chấm trong chuỗi?

>>> x = "google" 
>>> x is "google" 
True 
>>> x = "google.com" 
>>> x is "google.com" 
False 
>>> 

Tại sao lại như vậy?

Để đảm bảo điều này đúng, tôi đã thử nghiệm trên Python 2.5.4, 2.6.5, 2.7b2, Python 3.1 trên windows và Python 2.7b1 trên Linux.

Dường như có sự nhất quán trên tất cả chúng, do đó, theo thiết kế. Tui bỏ lỡ điều gì vậy?

Tôi chỉ tìm ra rằng từ một số tập lệnh lọc miền cá nhân của tôi không thực hiện được điều đó.

+10

Rất thích. Đó là một điều kỳ lạ. –

+2

Cả hai đều là 'False' trong Python 2.5.2. –

+3

Trong ActivePython 2.5.4.4, xem kết quả tương tự như OP. Gần như chắc chắn có một cái gì đó để làm với chuỗi interning, phải không? –

Trả lời

89

is thẩm tra đối tượng danh tính, và bất kỳ việc thực hiện Python, khi nó đáp ứng đen của loại không thay đổi, là hoàn toàn miễn phí để hoặc làm cho một đối tượng mới của loại bất biến, hoặc tìm kiếm thông qua các đối tượng hiện có của loại hình đó để xem nếu một số trong số chúng có thể được tái sử dụng (bằng cách thêm một tham chiếu mới vào cùng một đối tượng cơ bản). Đây là một lựa chọn tối ưu thực dụng và không phải là tùy thuộc vào ràng buộc ngữ nghĩa, vì vậy mã của bạn sẽ không bao giờ dựa vào đường dẫn nào mà việc thực hiện cung cấp có thể thực hiện (hoặc nó có thể phá vỡ với bản phát hành lỗi/tối ưu hóa của Python!).

Hãy xem xét ví dụ:

>>> import dis 
>>> def f(): 
... x = 'google.com' 
... return x is 'google.com' 
... 
>>> dis.dis(f) 
    2   0 LOAD_CONST    1 ('google.com') 
       3 STORE_FAST    0 (x) 

    3   6 LOAD_FAST    0 (x) 
       9 LOAD_CONST    1 ('google.com') 
      12 COMPARE_OP    8 (is) 
      15 RETURN_VALUE  

như vậy trong thực hiện đặc biệt này, trong vòng một hàm, quan sát của bạn không áp dụng và chỉ có một đối tượng được thực hiện cho các chữ (bất kỳ nghĩa đen), và thực tế:

>>> f() 
True 

Thực tế là vì trong một hàm thực hiện qua bảng hằng số hằng số (để tiết kiệm bộ nhớ bằng cách không tạo nhiều đối tượng bất biến không đổi) giá rẻ và nhanh chóng, và có thể cung cấp hiệu suất tốt trở lại kể từ khi chức năng có thể được gọi là nhiều lần sau đó.

Nhưng, việc thực hiện rất giống nhau, tại dấu nhắc tương tác (Sửa: Tôi ban đầu nghĩ điều này cũng sẽ xảy ra ở cấp cao nhất của một mô-đun, nhưng một lời nhận xét của @Thomas thiết tôi ngay, xem phần sau):

>>> x = 'google.com' 
>>> y = 'google.com' 
>>> id(x), id(y) 
(4213000, 4290864) 

KHÔNG bận tâm đến việc cố gắng lưu bộ nhớ theo cách đó - id s khác nhau, nghĩa là các đối tượng riêng biệt. Có khả năng chi phí cao hơn và lợi nhuận thấp hơn và do đó các chẩn đoán của trình tối ưu hóa thực hiện này cho biết nó không làm phiền tìm kiếm và chỉ cần đi trước. ví dụ như ở cấp cao nhất mô-đun, mỗi quan sát @Thomas', đưa ra::

Sửa

$ cat aaa.py 
x = 'google.com' 
y = 'google.com' 
print id(x), id(y) 

một lần nữa chúng ta thấy bảng-of-hằng số dựa trên bộ nhớ tối ưu hóa trong việc thực hiện này:

>>> import aaa 
4291104 4291104 

(kết thúc chỉnh sửa theo quan sát @Thomas).

Cuối cùng, một lần nữa về việc thực hiện giống nhau:

>>> x = 'google' 
>>> y = 'google' 
>>> id(x), id(y) 
(2484672, 2484672) 

các chẩn đoán khác nhau ở đây vì chuỗi chữ "trông giống như nó có thể là một định danh" - vì vậy nó có thể được sử dụng trong hoạt động đòi hỏi phải thực tập .. Vì vậy, trình tối ưu hóa thực hiện nó anyway (và một lần tập trung, tìm kiếm nó trở nên rất nhanh tất nhiên). Và quả thực, sự ngạc nhiên bất ngờ ...:

>>> z = intern(x) 
>>> id(z) 
2484672 

... x được intern ed lần đầu tiên (như bạn thấy, giá trị trả về của interncùng một đối tượng như xy , vì nó có cùng số id()). Tất nhiên, bạn cũng không nên dựa vào điều này - trình tối ưu hóa không tự động thực hiện bất cứ điều gì, nó chỉ là một cách tối ưu hóa heuristic; nếu bạn cần intern chuỗi ed, intern chúng một cách rõ ràng, chỉ để được an toàn. Khi bạn làm chuỗi thực tập một cách rõ ràng ...:

>>> x = intern('google.com') 
>>> y = intern('google.com') 
>>> id(x), id(y) 
(4213000, 4213000) 

... sau đó bạn làm đảm bảo chính xác cùng một đối tượng (ví dụ, cùng id()) kết quả mỗi lần - vì vậy bạn có thể áp dụng vi -optimizations như kiểm tra với is chứ không phải là == (Tôi đã hầu như không bao giờ tìm thấy đạt được hiệu suất tối thiểu để có giá trị phiền ;-).

Sửa: chỉ cần làm rõ, đây là những loại khác biệt hiệu suất Tôi đang nói về, trên một chậm Macbook Air ...:

$ python -mtimeit -s"a='google';b='google'" 'a==b' 
10000000 loops, best of 3: 0.132 usec per loop 
$ python -mtimeit -s"a='google';b='google'" 'a is b' 
10000000 loops, best of 3: 0.107 usec per loop 
$ python -mtimeit -s"a='goo.gle';b='goo.gle'" 'a==b' 
10000000 loops, best of 3: 0.132 usec per loop 
$ python -mtimeit -s"a='google';b='google'" 'a is b' 
10000000 loops, best of 3: 0.106 usec per loop 
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a is b' 
10000000 loops, best of 3: 0.0966 usec per loop 
$ python -mtimeit -s"a=intern('goo.gle');b=intern('goo.gle')" 'a == b' 
10000000 loops, best of 3: 0.126 usec per loop 

... vài chục nano giây hoặc cách, nhiều nhất. Vì vậy, giá trị thậm chí suy nghĩ về chỉ trong khắc nghiệt nhất "tối ưu hóa [expletive xóa] ra khỏi này [expletive xóa] hiệu suất nút cổ chai" tình huống! -)

+8

Có vẻ như tôi đang lạm dụng ** là ** nhà điều hành – YOU

+1

@ S.Mark, có thể, nhưng không nhất thiết - hãy xem chỉnh sửa của tôi về việc thực tập. Bạn thường sử dụng 'is' chỉ trên mutables như danh sách, và singletons như' None', nhưng nếu bạn đã đảm bảo thực tập (sau đó là một tối ưu hóa thực sự) bạn cũng có thể sử dụng nó ở đó (interning cũng làm cho '==' kiểm tra một chút wee nhanh hơn mặc dù, vì vậy bạn có thể không cần phải chèn 'là' ngay cả khi bạn ** làm tôn giáo thực tập tất cả các chuỗi có liên quan! -). –

+2

Alex, bạn nói "ở cấp cao nhất của mô-đun (hoặc dấu nhắc tương tác)", nhưng tôi tin những gì bạn mô tả (và những gì OP thấy) * chỉ * xảy ra tại dấu nhắc tương tác - cấp cao nhất của mô-đun vẫn được biên dịch thành một đối tượng mã đơn và tất cả các tham chiếu đến cùng một hằng số trong toàn bộ đối tượng mã đó sử dụng cùng một tham chiếu. –

15

"is" là một kiểm tra danh tính. Python có một số hành vi bộ nhớ đệm cho số nguyên nhỏ và (rõ ràng) dây. "là" được sử dụng tốt nhất để thử nghiệm singleton (ví dụ: None).

>>> x = "google" 
>>> x is "google" 
True 
>>> id(x) 
32553984L 
>>> id("google") 
32553984L 
>>> x = "google.com" 
>>> x is "google.com" 
False 
>>> id(x) 
32649320L 
>>> id("google.com") 
37787888L 
Các vấn đề liên quan