Có sự khác biệt giữa ==
và is
trong Python?
Vâng, họ có một sự khác biệt rất quan trọng.
==
: kiểm tra sự bằng nhau - ngữ nghĩa là các đối tượng tương đương (không nhất thiết phải cùng một đối tượng) sẽ kiểm tra như nhau. Như tài liệu nói :
Các toán tử <,>, ==,> =, <= và! = So sánh giá trị của hai đối tượng.
is
: kiểm tra danh tính - ngữ nghĩa là đối tượng (như được giữ trong bộ nhớ) là đối tượng. Một lần nữa, tài liệu nói :
Các toán tử is
và is not
kiểm tra nhận dạng đối tượng: x is y
là đúng khi và chỉ khi x
và y
là cùng một đối tượng. Nhận dạng đối tượng được xác định bằng cách sử dụng id()
chức năng. x is not y
mang lại giá trị thật ngược.
Do đó, việc kiểm tra danh tính cũng giống như kiểm tra sự bằng nhau của ID của các đối tượng. Đó là,
a is b
giống như:
id(a) == id(b)
trong đó id
hàm dựng sẵn trả về một số nguyên "được đảm bảo là duy nhất trong số các đối tượng hiện có đồng thời" (xem help(id)
) và ở đâu a
và b
là bất kỳ đối tượng tùy ý nào.
Hướng dẫn sử dụng khác
Bạn nên sử dụng những so sánh này cho ngữ nghĩa của họ. Sử dụng is
để kiểm tra danh tính và ==
kiểm tra sự bình đẳng.
Vì vậy, nói chung, chúng tôi sử dụng is
để kiểm tra danh tính. Điều này thường hữu ích khi chúng ta đang kiểm tra một đối tượng chỉ tồn tại một lần trong bộ nhớ, được gọi là "singleton" trong tài liệu.
Các trường hợp sử dụng is
bao gồm:
None
- giá trị enum (khi sử dụng Enums từ mô-đun enum)
- mô-đun thường
- thường là các đối tượng lớp kết quả từ định nghĩa lớp
- thường là các đối tượng hàm do các định nghĩa hàm
- bất cứ điều gì khác chỉ nên tồn tại một lần trong bộ nhớ (nói chung là tất cả các singletons)
- một đối tượng cụ thể mà bạn muốn theo danh tính
Các trường hợp sử dụng thông thường ==
bao gồm:
- số, bao gồm số nguyên
- dây
- danh sách
- bộ
- từ điển
- đối tượng biến đổi tùy chỉnh
- đối tượng bất biến dựng sẵn khác, trong hầu hết các trường hợp
Các trường hợp sử dụng chung, một lần nữa, cho ==
, là đối tượng mà bạn muốn thể không phải là cùng một đối tượng, thay vào đó nó có thể là một tương đương một
PEP 8 hướng
PEP 8, hướng dẫn kiểu Python chính thức cho thư viện chuẩn cũng đề cập đến hai trường hợp sử dụng chois
:
Việc so sánh với các singletons như vậy None
phải luôn luôn được thực hiện với is
hoặc
is not
, không bao giờ là các toán tử đẳng thức.
Ngoài ra, hãy cẩn thận if x
khi viết khi bạn thực sự có ý nghĩa if x is not None
- ví dụ như khi kiểm tra xem một biến hoặc đối số mặc định None
được đặt thành một số giá trị khác. Giá trị khác có thể có một loại (chẳng hạn như một thùng chứa) có thể sai trong bối cảnh boolean!
Suy ra sự bình đẳng từ bản sắc
Nếu is
là đúng, sự bình đẳng thường có thể được suy ra - về mặt logic, nếu một đối tượng là chính nó, thì nó nên kiểm tra tương đương với chính nó.
Trong hầu hết các trường hợp logic này là đúng, nhưng nó phụ thuộc vào việc thực hiện __eq__
phương pháp đặc biệt. Như các tài liệu nói,
Hành vi mặc định để so sánh bằng ( ==
và !=
) dựa trên danh tính của các đối tượng. Do đó, so sánh bình đẳng của các thể hiện có cùng một danh tính dẫn đến sự bình đẳng và so sánh bình đẳng của các thể hiện với các danh tính khác nhau dẫn đến sự bất bình đẳng. Một động lực cho hành vi mặc định này là mong muốn rằng tất cả các đối tượng nên phản xạ (tức là x là y ngụ ý x == y).
và vì lợi ích của tính nhất quán, khuyến nghị:
So sánh bình đẳng nên được phản xạ. Nói cách khác, các đối tượng giống hệt nhau nên so sánh bằng nhau:
x is y
ngụ ý x == y
Chúng ta có thể thấy rằng đây là hành vi mặc định cho các đối tượng tùy chỉnh:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
Thông tin chi tiết cũng thường đúng - nếu đôi khi kiểm tra là không bằng nhau, bạn thường có thể suy ra rằng chúng không phải là cùng một đối tượng.
Vì các thử nghiệm cho sự bình đẳng có thể được tùy chỉnh, suy luận này không phải lúc nào cũng đúng với tất cả các loại.
Một ngoại lệ
Một ngoại lệ đáng chú ý là nan
- nó luôn kiểm tra là không bằng chính nó:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
Kiểm tra danh tính có thể là một kiểm tra nhanh hơn nhiều so với kiểm tra sự bình đẳng (có thể yêu cầu kiểm tra đệ quy các thành viên).
Nhưng nó không thể được thay thế cho sự bình đẳng nơi bạn có thể tìm thấy nhiều hơn một đối tượng là tương đương.
Lưu ý rằng so sánh sự bình đẳng của danh sách và bộ dữ liệu sẽ cho rằng danh tính của các đối tượng là bằng nhau (vì đây là kiểm tra nhanh). Điều này có thể tạo ra mâu thuẫn nếu logic không nhất quán - vì nó dành cho nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Một câu chuyện thận trọng:
Câu hỏi đang cố gắng sử dụng is
để so sánh các số nguyên. Bạn không nên cho rằng một thể hiện của một số nguyên là cùng một thể hiện với một tham chiếu khác. Câu chuyện này giải thích tại sao.
Một nhà bình luận có mã dựa trên thực tế là các số nguyên nhỏ (bao gồm từ 5 đến 256) là các singletons trong Python, thay vì kiểm tra sự bằng nhau.
Wow, điều này có thể dẫn đến một số lỗi quỷ quyệt. Tôi đã có một số mã kiểm tra nếu a là b, hoạt động như tôi muốn vì a và b thường là các số nhỏ. Lỗi chỉ xảy ra hôm nay, sau sáu tháng sản xuất, vì a và b cuối cùng đủ lớn để không bị lưu vào bộ nhớ cache. - gwg
Nó đã làm việc trong sự phát triển. Nó có thể đã vượt qua một số khó khăn.
Và nó đã hoạt động trong sản xuất - cho đến khi mã kiểm tra một số nguyên lớn hơn 256, tại thời điểm đó nó đã thất bại trong sản xuất.
Đây là một lỗi sản xuất có thể đã bị bắt trong đánh giá mã hoặc có thể với trình kiểm tra kiểu.
Hãy để tôi nhấn mạnh: không sử dụng is
để so sánh các số nguyên.
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
đầu ra :False True False
.