Có sự khác biệt nào giữa các foo của Foo không


217

Có sự khác biệt nào giữa:

if foo is None: pass

if foo == None: pass

Quy ước mà tôi đã thấy trong hầu hết các mã Python (và mã tôi tự viết) là quy tắc trước đây, nhưng gần đây tôi đã bắt gặp mã sử dụng mã sau. Không có trường hợp nào (và là trường hợp duy nhất, IIRC) của noneType, vì vậy nó không thành vấn đề, phải không? Có bất kỳ trường hợp nào trong đó nó có thể?

Câu trả lời:


253

isluôn trả về Truenếu so sánh cùng thể hiện đối tượng

Trong khi ==cuối cùng được xác định bằng __eq__()phương pháp

I E


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False

51
Bạn có thể muốn thêm rằng Không ai là người độc thân nên "Không ai là Không" luôn luôn Đúng.
e-satis

43
Và bạn có thể muốn thêm rằng istoán tử không thể được tùy chỉnh (bị quá tải bởi một lớp do người dùng định nghĩa).
martineau

@study Phương thức __eq__(self)này là một phương thức dựng sẵn đặc biệt xác định cách ==xử lý khi được sử dụng trên một đối tượng Python. Ở đây chúng ta đã ghi đè nó để khi ==được sử dụng trên các đối tượng loại Foonó luôn trả về đúng. Không có một phương thức tương đương cho istoán tử và vì vậy hành vi iskhông thể thay đổi theo cùng một cách.
Brendan

Có phải vì định nghĩa của lớp foo không có hàm tạo, tức là hàm init ?
học ngày

49

Bạn có thể muốn đọc danh tính và tương đương đối tượng này .

Câu lệnh 'is' được sử dụng cho danh tính đối tượng, nó kiểm tra xem các đối tượng có tham chiếu đến cùng một thể hiện (cùng một địa chỉ trong bộ nhớ) hay không.

Và câu lệnh '==' đề cập đến đẳng thức (cùng giá trị).


Hmmm, tôi nghĩ rằng liên kết của bạn đã thay đổi, trừ khi bạn quan tâm đến cách gọi các chức năng bên ngoài từ python
Pat

Tôi vừa thử a=1;b=1;print(a is b) # True. Bất kỳ ý tưởng tại sao a is bhóa ra là đúng ngay cả khi chúng dường như là 2 đối tượng khác nhau (địa chỉ khác nhau trong bộ nhớ)?
Johnny Chiu

24

Một lời cảnh báo:

if foo:
  # do something

không chính xác giống như:

if x is not None:
  # do something

Cái trước là một bài kiểm tra giá trị boolean và có thể đánh giá thành false trong các bối cảnh khác nhau. Có một số điều đại diện cho sai trong kiểm tra giá trị boolean, ví dụ như các thùng chứa rỗng, giá trị boolean. Không ai cũng đánh giá là sai trong tình huống này nhưng những thứ khác cũng vậy.


12

(ob1 is ob2) tương đương với (id(ob1) == id(ob2))


6
... nhưng (ob là ob2) nhanh hơn rất nhiều. Timeit nói "(a là b)" là 0,0365 usec mỗi vòng và "(id (a) == id (b))" là 0,153 usec mỗi vòng. Nhanh hơn 4.2 lần!
AKX

4
các isphiên bản không cần gọi hàm, và không có tra cứu thuộc tính python-phiên dịch ở tất cả; thông dịch viên có thể trả lời ngay nếu ob1 thực tế là ob2.
u0b34a0f6ae

17
Không nó không. {} is {}là sai và id({}) == id({})có thể (và trong CPython) đúng. Xem stackoverflow.com/questions/3877230
Piotr Dobrogost

12

Lý do foo is Nonelà cách ưa thích là bạn có thể xử lý một đối tượng tự xác định __eq__và đối tượng đó xác định đối tượng bằng với Không. Vì vậy, luôn luôn sử dụng foo is Nonenếu bạn cần xem nó còn nguyên vẹn không None.


8

Không có sự khác biệt bởi vì các đối tượng giống hệt nhau tất nhiên sẽ bằng nhau. Tuy nhiên, PEP 8 nêu rõ bạn nên sử dụng is:

Việc so sánh với các singletons như Không nên luôn luôn được thực hiện với hoặc không, không bao giờ là các toán tử đẳng thức.


7

iskiểm tra danh tính, không bình đẳng. Cho tuyên bố của bạnfoo is none , Python chỉ cần so sánh địa chỉ bộ nhớ của các đối tượng. Nó có nghĩa là bạn đang đặt câu hỏi "Tôi có hai tên cho cùng một đối tượng không?"

==mặt khác kiểm tra sự bằng nhau như được xác định bằng __eq__()phương pháp. Nó không quan tâm đến danh tính.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Nonelà một nhà điều hành singleton. Như vậy None is Nonelà luôn luôn đúng.

In [101]: None is None
Out[101]: True

5

Đối với Không nên không có sự khác biệt giữa bình đẳng (==) và danh tính (là). Không có loại nào có thể trả về danh tính cho sự bình đẳng. Vì Không có trường hợp nào là trường hợp duy nhất bạn có thể tạo ra Không có Loại (tôi nghĩ điều này là đúng), hai thao tác là như nhau. Trong trường hợp của các loại khác, điều này không phải lúc nào cũng đúng. Ví dụ:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Điều này sẽ in "Bằng" vì các danh sách có thao tác so sánh không phải là trả về mặc định danh tính.


5

@ Jason :

Tôi khuyên bạn nên sử dụng một cái gì đó nhiều hơn dọc theo dòng

if foo:
    #foo isn't None
else:
    #foo is None

Tôi không thích sử dụng "if foo:" trừ khi foo thực sự đại diện cho giá trị boolean (tức là 0 hoặc 1). Nếu foo là một chuỗi hoặc một đối tượng hoặc một cái gì đó khác, "nếu foo:" có thể hoạt động, nhưng nó trông giống như một lối tắt lười biếng đối với tôi. Nếu bạn đang kiểm tra xem x có phải là Không, hãy nói "nếu x là Không:".


Kiểm tra các chuỗi / danh sách trống với "if var" là cách ưa thích. Chuyển đổi Boolean được xác định rõ và ít mã hơn thậm chí hoạt động tốt hơn. Chẳng có lý do gì để làm "if len (mylist) == 0" chẳng hạn.
truppo

Sai lầm. Giả sử foo = "". Sau đó if foosẽ trả lại sai và nhận xét #foo is Nonelà sai.
blo siêu

Lưu ý đối với downvoters - câu trả lời của tôi là trích dẫn một câu trả lời đã bị xóa và không đồng ý với nó. Nếu bạn không giống như các mã trong câu trả lời của tôi, bạn cần phải upvote . :-)
Graeme Perrow

2

Một số chi tiết:

  1. Các iskhoản thực sự kiểm tra nếu hai objects đang ở vị trí nhớ cùng hay không. tức là liệu cả hai đều trỏ đến cùng một vị trí bộ nhớ và có cùng một vị trí hay không id.

  2. Theo kết quả của 1, isđảm bảo có hay không, hai objects được biểu diễn từ vựng có thuộc tính giống hệt nhau (thuộc tính của thuộc tính ...) hay không

  3. Õ của loại nguyên thủy như bool, int, string(với một số ngoại lệ), NoneTypecó giá trị tương tự sẽ luôn luôn ở trong vị trí nhớ cùng.

Ví dụ

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

Và vì NoneTypechỉ có thể có một phiên bản của chính nó trong bảng "tra cứu" của con trăn, do đó, cái trước và cái sau mang phong cách lập trình của nhà phát triển đã viết mã (có thể để thống nhất) thay vì có bất kỳ lý do logic tinh tế nào để chọn cái này qua cái khác


2
Mọi người đọc điều này: KHÔNG sử dụng some_string is "bar"để so sánh các chuỗi EVER. KHÔNG CÓ MỘT LÝ DO CHẤP NHẬN HẤP DẪN để làm như vậy và nó S BRE NÓI khi bạn không mong đợi nó. Thực tế là nó hoạt động thường đơn giản là vì CPython biết rằng sẽ thật ngu ngốc khi tạo ra hai đối tượng bất biến có cùng nội dung. Nhưng nó có thể xảy ra dù sao.
ThiefMaster

@ThiefMaster câu trả lời có xu hướng bị hiểu sai không? Mặc dù, khi đọc lại, tôi không thể tìm thấy nó (với việc đề cập đến "một số ngoại lệ"). Tuyên bố của bạn chỉ giữ cho chuỗi và không int, phải không?
Chảy máu ngón tay

Không thực sự, nhưng vì bạn có ví dụ đó trong câu trả lời của mình, tôi nghĩ rằng đó là một ý tưởng tốt để cảnh báo người dùng rằng thực sự sử dụng nó là một ý tưởng tồi. Có thể thêm một cái gì đó như "# cpython cụ thể / không được bảo đảm" đằng sau dòng đó ...
ThiefMaster

1

Kết luận của John Machin Nonelà một đơn là kết luận được củng cố bởi mã này.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Nonelà một người độc thân, x == Nonex is Nonesẽ có kết quả tương tự. Tuy nhiên, theo quan điểm thẩm mỹ của tôi, x == Nonelà tốt nhất.


2
Tôi không đồng ý với ý kiến ​​ở cuối câu trả lời này. Khi so sánh với không rõ ràng, thường có ý định rằng đối tượng trong câu hỏi chính xác là Noneđối tượng. Khi so sánh, một người hiếm khi thấy Không được sử dụng trong bất kỳ bối cảnh nào khác ngoại trừ tương tự Falsevới các giá trị khác là sự thật. Trong những trường hợp đó, thành ngữ sẽ dễ hiểu hơnif x: pass
SingleNegationElimination 27/03

0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.