2008-08-25 35 views
207

Có sự khác biệt giữa:Có sự khác biệt nào giữa "foo is None" và "foo == None" không?

if foo is None: pass 

if foo == None: pass 

Quy ước mà tôi đã nhìn thấy ở hầu hết các mã Python (và mã bản thân tôi viết) là cựu, nhưng gần đây tôi đi trên mã sử dụng sau này. Không có gì là một cá thể (và cá thể duy nhất, IIRC) của NoneType, vì vậy nó không quan trọng, phải không? Có bất kỳ hoàn cảnh nào trong đó có thể không?

Trả lời

239

is luôn trả True nếu nó so sánh trường hợp đối tượng cùng

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

ví dụ:


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

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

Bạn có thể muốn thêm rằng Không có gì là một singleton để "Không có gì là Không" luôn đúng. –

+39

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

+0

Vì vậy, trong trường hợp của bạn, tại sao mã "f == Không" trả về True? Bối rối ... – study

47

Bạn có thể muốn đọc object identity and equivalence này.

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

Và câu lệnh '==' đề cập đến bình đẳng (cùng một giá trị).

+0

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

4

Đối với Không, không nên có sự khác biệt giữa bình đẳng (==) và nhận dạng (là). NoneType có thể trả về danh tính cho sự bình đẳng. Vì None là trường hợp duy nhất bạn có thể làm cho NoneType (tôi nghĩ điều này là đúng), hai hoạt động giống nhau. Trong trường hợp các loại khác, điều này không phải luôn luôn như vậy. 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ình đẳng" vì danh sách có hoạt động so sánh không phải là nhận dạng mặc định.

4

@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 của

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

tôi không thích sử dụng "nếu foo:" trừ khi foo thực sự đại diện cho một 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ể làm việc, nhưng nó trông giống như một phím tắt lười biếng với tôi. Nếu bạn đang kiểm tra xem liệu x là Không, hãy nói "if x is None:".

+0

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

+0

Sai. Giả sử foo = "". Sau đó 'if foo' sẽ trả về false và chú thích' #foo là None' là sai. – blokeley

+0

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 thích mã trong câu trả lời của tôi, bạn cần phải _upvote_. :-) –

23

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ác cựu là một thử nghiệm giá trị boolean và có thể đánh giá là false trong những bối cảnh khác nhau. Có một số thứ đại diện cho sai trong một thử nghiệm giá trị boolean ví dụ các thùng chứa rỗng, các giá trị boolean. Không ai cũng đánh giá sai trong tình huống này nhưng những thứ khác cũng vậy.

12

(ob1 is ob2) bằng (id(ob1) == id(ob2))

+6

... nhưng (ob là ob2) là LOT nhanh hơn. Timeit nói "(a là b)" là 0,0365 usec mỗi vòng lặp và "(id (a) == id (b))" là 0,153 usec mỗi vòng lặp. 4.2x nhanh hơn! – AKX

+4

phiên bản 'is' không cần gọi hàm và không tra cứu thuộc tính python-interpreter; người thông dịch ngay lập tức có thể trả lời nếu ob1, trên thực tế, ob2. – u0b34a0f6ae

+15

Không, nó không. '{} là {}' là sai và 'id ({}) == id ({})' có thể (và ** là ** trong CPython) đúng. Xem http://stackoverflow.com/questions/3877230 –

11

Lý do foo is None là cách ưa thích là bạn có thể được xử lý một đối tượng mà định nghĩa riêng của mình __eq__, và xác định các đối tượng được bằng None. Vì vậy, hãy luôn sử dụng foo is None nếu bạn cần xem liệu nó có bị ảnh hưởng không None.

1

Kết luận của John Machin rằng None là một singleton 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 
>>> 

Kể từ None là một singleton, x == Nonex is None sẽ có kết quả tương tự. Tuy nhiên, theo ý kiến ​​thẩm mỹ của tôi, x == None là 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 không rõ ràng, thường thì đối tượng được đề cập chính xác là đối tượng 'None'. Bằng cách so sánh, một ít khi thấy Không được sử dụng trong bất kỳ ngữ cảnh nào khác ngoại trừ tương tự với 'False' với các giá trị khác là sự thật. Trong những trường hợp đó, nó thành ngữ hơn để làm một cái gì đó như 'if x: pass' – SingleNegationElimination

1

Một số chi tiết:

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

  2. Như một hệ quả của 1, is đảm bảo hay không, hay không, hai lexically đại diện object s có các thuộc tính giống hệt nhau (thuộc tính-of-thuộc tính ...) hoặc không

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

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à kể từ NoneType chỉ có thể có một thể hiện của bản thân trong bảng "nhìn lên" của python vì vậy trước đây và sau này là nhiều hơn một phong cách lập trình của nhà phát triển người viết mã (có thể cho phù hợp) thay vì sau đó có bất kỳ lý do hợp lý tinh tế nào để chọn một lý do khác.

+2

Mọi người đều đọc điều này: KHÔNG sử dụng' some_string là "bar" 'để so sánh các chuỗi EVER. Không có một REASON CHẤP NHẬN SINGLE để làm như vậy và nó S BREAK BREAK khi bạn không mong đợi nó. Thực tế là nó hoạt động thường xuyên chỉ đơn giản là vì CPython biết nó sẽ là ngu ngốc để 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

+0

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

+0

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

8

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

So sánh để độc thân như Không nên luôn luôn được thực hiện với là hoặc không phải là, không bao giờ các nhà khai thác bình đẳng.

4

is kiểm tra danh tính, không bình đẳng. Đối với tuyên bố của bạn foo 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 tính bình đẳng như được xác định theo phương pháp __eq__(). Nó không quan tâm đến bản sắc.

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 

None là một toán tử đơn. Vì vậy, None is None luôn đúng.

In [101]: None is None 
Out[101]: True 
Các vấn đề liên quan