0 <0 == 0 ifadesi Python'da neden False döndürüyor?


136

Python 2.6 Queue.py bakarak, ben biraz garip buldum bu yapı bulundu:

def full(self):
    """Return True if the queue is full, False otherwise
    (not reliable!)."""
    self.mutex.acquire()
    n = 0 < self.maxsize == self._qsize()
    self.mutex.release()
    return n

Eğer maxsize0'dır kuyruk asla doludur.

Benim sorum bu dava için nasıl çalışıyor? 0 < 0 == 0Yanlış olarak nasıl değerlendirilir?

>>> 0 < 0 == 0
False
>>> (0) < (0 == 0)
True
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True

0 <True, python'da False değerine eşit mi?
Marino Šimić

3
@Marino Šimić: OP'nin sorusunda gösterilen ikinci örnekten >>> (0) < (0 == 0)açıkça değil.
martineau

3
n = 0 < self.maxsize == self._qsize()İlk etapta olduğu gibi herhangi bir dilde kod yazmamalısınız. Neler olup bittiğini anlamak için gözlerinizin çizgiyi birkaç kez ileri geri dartması gerekiyorsa, bu iyi yazılmış bir çizgi değildir. Sadece birkaç satıra ayırın.
BlueRaja - Danny Pflughoeft

2
@Mavi: Böyle bir karşılaştırma yapmamaya katılıyorum ama ayrı satırlara bölmek iki karşılaştırma için biraz denize düşüyor. Umarım bunu ayrı karşılaştırmalara ayırırsınız. ;)
Jeff Mercado

2
@Mavi: Yazmadım, Python 2.6'da. Sadece neler olduğunu anlamaya çalışıyordum.
Marcelo Santos

Yanıtlar:


113

Python'un aralık karşılaştırmaları ifade etmeyi kolaylaştırmak için ilişkisel operatör dizileri için özel durum yönetimi olduğuna inanıyorum. Söylemekten 0 < x <= 5çok söylemek daha güzel (0 < x) and (x <= 5).

Bunlara zincirleme karşılaştırmalar denir . Ve bu onlar için belgelere bir bağlantı.

Bahsettiğiniz diğer durumlarda, parantez bir ilişkisel operatörü diğerinden önce uygulanmaya zorlar ve böylece artık zincirleme karşılaştırmalar olmaz. Beri Trueve Falsetamsayı olarak değerlere sahip size parantez versiyonları dışında yapmak cevap almak.


bu karşılaştırmalardan bazılarını denemek ve int () ve bool () belirtmek ilginçtir. Sıfırdan herhangi birinin
boolunun

Bunun yerine bu bölüme bağlantı vermek istediniz mi? docs.python.org/2/reference/expressions.html#comparisons
tavnab

@tavnab - Evet. Düzeltmeyi hatırlamaya çalışacağım. Ayrıca düzenleme geçmişini de kontrol edeceğim. Yapacağım bir hata gibi görünmüyor. 😕
Şeye Giden

42

Çünkü

(0 < 0) and (0 == 0)

olduğunu False. Karşılaştırma işleçlerini birbirine bağlayabilirsiniz ve bunlar otomatik olarak ikili karşılaştırmalara genişletilir.


EDIT - Python Doğru ve Yanlış hakkında açıklama

Python Trueve Falsesadece örnekleri bool, bir alt sınıfı olan int. Başka bir deyişle, Truegerçekten sadece 1'dir.

Bunun amacı, bir tamsayı gibi bir boole karşılaştırmasının sonucunu kullanabilmenizdir. Bu,

>>> (1==1)+(1==1)
2
>>> (2<1)<1
True

Ancak bunlar yalnızca karşılaştırmaları parantez içine alırsanız gerçekleşir, böylece önce değerlendirilirler. Aksi takdirde Python karşılaştırma işleçlerini genişletir.


2
Dün boole değerlerinin tamsayı olarak kullanıldığını ilginç bir şekilde gördüm. İfade 'success' if result_code == 0 else 'failure', daha ('error', 'success')[result_code == 0]önce bir listede / gruptaki bir öğeyi seçmek için kullanılan bir boole görmediğim için yeniden yazılabilir .
Andrew Clark

Python 2.2'nin etrafına 'bool' eklendi.
MRAB

18

Yaşadığınız garip davranış, pitonların koşulları zincirleme yeteneğinden kaynaklanıyor. 0'ın 0'dan küçük olmadığını tespit ettiğinden, tüm ifadenin false olarak değerlendirilmesine karar verir. Bunu ayrı koşullara ayırır ayırmaz, işlevselliği değiştirirsiniz. Başlangıçta esasen o test ediyor a < b && b == c, orijinal ifadesi için a < b == c.

Başka bir örnek:

>>> 1 < 5 < 3
False

>>> (1 < 5) < 3
True

1
OMG, OO a < b && b == cile aynıa < b == c
Kiril Kirov

9
>>> 0 < 0 == 0
False

Bu zincirleme bir karşılaştırma. Her bir ikili karşılaştırma sırayla doğruysa true değerini döndürür. Eşdeğerdir(0 < 0) and (0 == 0)

>>> (0) < (0 == 0)
True

Bu, 0 < TrueTrue olarak değerlendirilene eşdeğerdir .

>>> (0 < 0) == 0
True

Bu, False == 0True olarak değerlendirilene eşdeğerdir .

>>> 0 < (0 == 0)
True

0 < TrueYukarıdaki gibi True olarak değerlendirilene eşdeğerdir .


7

Sökmeye (bayt kodları) bakarak neden 0 < 0 == 0olduğu açıktır False.

İşte bu ifadenin bir analizi:

>>>import dis

>>>def f():
...    0 < 0 == 0

>>>dis.dis(f)
  2      0 LOAD_CONST               1 (0)
         3 LOAD_CONST               1 (0)
         6 DUP_TOP
         7 ROT_THREE
         8 COMPARE_OP               0 (<)
        11 JUMP_IF_FALSE_OR_POP    23
        14 LOAD_CONST               1 (0)
        17 COMPARE_OP               2 (==)
        20 JUMP_FORWARD             2 (to 25)
   >>   23 ROT_TWO
        24 POP_TOP
   >>   25 POP_TOP
        26 LOAD_CONST               0 (None)
        29 RETURN_VALUE

Uyarı satırları 0-8: Bu satırlar 0 < 0açıkça Falsepython yığınına dönüp dönmediğini kontrol eder .

Şimdi 11. satıra dikkat edin: JUMP_IF_FALSE_OR_POP 23 Bu, 0 < 0döndürmeler False23 numaralı satıra bir atlama gerçekleştirdiği anlamına gelir .

Şimdi 0 < 0edilir False, böylece atlama ile yığını bırakır, alınır bir Falsebütün ifadesi için dönüş değeri olan 0 < 0 == 0rağmen == 0parçası bile kontrol edilmez.

Sonuç olarak, cevap bu sorunun diğer cevaplarında olduğu gibi. 0 < 0 == 0özel bir anlamı var. Derleyici bunu iki terimle değerlendirir: 0 < 0ve 0 == 0. andAralarındaki karmaşık boole ifadelerinde olduğu gibi , birincisi başarısız olursa ikincisi bile kontrol edilmez.

Umarım bu biraz şeyleri aydınlatır ve umarım bu beklenmedik davranışı analiz etmek için kullandığım yöntemin başkalarını gelecekte de denemeye teşvik eder.


Belirli bir uygulamayı tersine mühendislik yapmak yerine spesifikasyondan çalışmak daha kolay olmaz mıydı?
David Heffernan

Hayır. Kısa cevap bu. Ben senin kişiliğine bağlı olduğuna inanıyorum. Eğer bir "kara kutu" görünümü ile ilgiliyseniz ve cevaplarınızı teknik özelliklerden ve belgelerden almayı tercih ediyorsanız, bu cevap sadece sizi şaşırtacaktır. Eğer şeylerin içini kazıp açıklamak isterseniz, bu cevap tam size göre. Bu tersine mühendisliğin sadece belirli bir uygulama ile ilgili olduğuna dair görüşünüz doğrudur ve belirtilmesi gerekir, ancak bu cevabın amacı bu değildi. Yeterince merak edenler için "kaputun altında" bir bakış atmanın python'da ne kadar kolay olduğunun bir göstergesidir.
SatA

1
Tersine mühendislik ile ilgili sorun, öngörücü güç eksikliğidir. Yeni bir dil öğrenmenin yolu değil.
David Heffernan

Eklemem gereken bir başka şey de, teknik özelliklerin ve belgelerin her zaman tam olmaması ve çoğu durumda bu tür özel durumlar için cevap vermemesidir. Sonra, inanıyorum ki, cevapları almak için gereken kadar araştırmak, araştırmak ve daha derine ulaşmaktan korkmamalıyız.
SatA

2

Diğerlerinin de belirttiği gibi x comparison_operator y comparison_operator z, (x comparison_operator y) and (y comparison_operator z)y'nin sadece bir kez değerlendirildiği bonusu ile sözdizimsel şekerdir .

Yani ifadeniz 0 < 0 == 0gerçekten (0 < 0) and (0 == 0), hangisinin False and Truesadece olduğunu değerlendirir False.


2

belki dokümanlardaki bu alıntı yardımcı olabilir:

Bunlar, “zengin karşılaştırma” yöntemleri olarak adlandırılır ve aşağıdakiler yerine karşılaştırma işleçleri için çağrılır __cmp__(). Aşağıdaki gibi operatör semboller ve yöntem adları arasındaki yazışmalar geçerli: x<yçağrılar x.__lt__(y), x<=yçağrılar x.__le__(y), x==yçağrılar x.__eq__(y), x!=yve x<>y çağrı x.__ne__(y), x>yçağrı x.__gt__(y)ve x>=yçağrılar x.__ge__(y).

Zengin bir karşılaştırma yöntemi, NotImplementedbelirli bir çift argüman için işlemi uygulamazsa singletonu döndürebilir . Sözleşme ile, Falseve Truebaşarılı bir karşılaştırma için iade edilir. Bununla birlikte, bu yöntemler herhangi bir değer döndürebilir, bu nedenle karşılaştırma operatörü bir Boolean bağlamında kullanılırsa (örneğin, bir if ifadesi durumunda), Python bool()sonucun doğru veya yanlış olup olmadığını belirlemek için değeri çağırır .

Karşılaştırma işleçleri arasında herhangi bir zımni ilişki yoktur. Gerçek, bunun yanlış olduğu x==yanlamına gelmez x!=y. Buna göre, tanımlarken __eq__(), __ne__()operatörlerin beklendiği gibi davranması için de tanımlanmalıdır . __hash__()Özel karşılaştırma işlemlerini destekleyen ve sözlük anahtarları olarak kullanılabilen yıkanabilir nesneler oluşturma hakkında bazı önemli notlar için paragrafa bakın .

Bu yöntemlerin takas argümanı sürümleri yoktur (sol argüman işlemi desteklemiyor, ancak sağ argüman destekliyorsa kullanılır); daha doğrusu, __lt__()ve __gt__() birbirlerinin yansımasıdır, __le__() ve __ge__()birbirlerinin yansımasıdır ve __eq__()ve __ne__() kendi yansımasıdır.

Zengin karşılaştırma yöntemlerine yönelik argümanlar hiçbir zaman zorlanmamaktadır.

Bunlar karşılaştırmalardı, ancak karşılaştırmaları zincirlediğiniz için şunu bilmelisiniz:

Karşılaştırmalar keyfi olarak zincirlenebilir, örn. Y'nin sadece bir kez değerlendirilmesi dışında x < y <= zeşdeğerdir x < y and y <= z(ancak her iki durumda da x <y yanlış olduğu tespit edildiğinde z hiç değerlendirilmez).

Resmi olarak, eğer a, b, c, ..., y, z ifadeler ve op1, op2, ..., opN karşılaştırma operatörleriyse, bir op1 b op2 c ... y opN z bir op1 b'ye eşdeğerse ve b op2 c ve ... y opN z, ancak her ifadenin en fazla bir kez değerlendirilmesi.


1

İşte tüm ihtişamıyla.

>>> class showme(object):
...   def __init__(self, name, value):
...     self.name, self.value = name, value
...   def __repr__(self):
...     return "<showme %s:%s>" % (self.name, self.value)
...   def __cmp__(self, other):
...     print "cmp(%r, %r)" % (self, other)
...     if type(other) == showme:
...       return cmp(self.value, other.value)
...     else:
...       return cmp(self.value, other)
... 
>>> showme(1,0) < showme(2,0) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
False
>>> (showme(1,0) < showme(2,0)) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
cmp(<showme 3:0>, False)
True
>>> showme(1,0) < (showme(2,0) == showme(3,0))
cmp(<showme 2:0>, <showme 3:0>)
cmp(<showme 1:0>, True)
True
>>> 

0

Bence Python sihir arasında tuhaf gidiyor. Ortalama 1 < 2 < 32 ile aynı 1 ile 3 arasındadır.

Bu durumda, [orta 0] 'ı [sol 0]' dan daha büyük ve [sağ 0] 'a eşit olduğunu düşünüyorum. Orta 0, sol 0'dan büyük değildir, bu nedenle yanlış olarak değerlendirilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.