Python'da "in" nin çağrışımı?


107

Bir Python ayrıştırıcısı yapıyorum ve bu gerçekten kafamı karıştırıyor:

>>>  1 in  []  in 'a'
False

>>> (1 in  []) in 'a'
TypeError: 'in <string>' requires string as left operand, not bool

>>>  1 in ([] in 'a')
TypeError: 'in <string>' requires string as left operand, not list

İlişkilendirme vb. Açısından Python'da "giriş" tam olarak nasıl çalışır?

Neden bu ifadelerden ikisi aynı şekilde davranmıyor?


6
Muhtemelen burada açıklanan davranışa denk geliyorsunuz : docs.python.org/reference/expressions.html#not-in , yazmanıza if a < b < c:ve sezgisel olarak çalıştırmanıza izin veren
millimoose

3
@millimoose: Evet, sanırım inbir "karşılaştırma" operatörü olarak hiç düşünmemiştim . : \
user541686

Yanıtlar:


123

1 in [] in 'a'olarak değerlendirilir (1 in []) and ([] in 'a').

İlk koşul ( 1 in []) olduğundan False, koşulun tamamı şu şekilde değerlendirilir False; ([] in 'a')hiçbir zaman gerçekte değerlendirilmez, bu nedenle herhangi bir hata ortaya çıkmaz.

İşte ifade tanımları:

In [121]: def func():
   .....:     return 1 in [] in 'a'
   .....: 

In [122]: dis.dis(func)
  2           0 LOAD_CONST               1 (1)
              3 BUILD_LIST               0
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               6 (in)
             11 JUMP_IF_FALSE            8 (to 22)  #if first comparison is wrong 
                                                    #then jump to 22, 
             14 POP_TOP             
             15 LOAD_CONST               2 ('a')
             18 COMPARE_OP               6 (in)     #this is never executed, so no Error
             21 RETURN_VALUE         
        >>   22 ROT_TWO             
             23 POP_TOP             
             24 RETURN_VALUE        

In [150]: def func1():
   .....:     return (1 in  []) in 'a'
   .....: 

In [151]: dis.dis(func1)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               3 (())
              6 COMPARE_OP               6 (in)   # perform 1 in []
              9 LOAD_CONST               2 ('a')  # now load 'a'
             12 COMPARE_OP               6 (in)   # compare result of (1 in []) with 'a'
                                                  # throws Error coz (False in 'a') is
                                                  # TypeError
             15 RETURN_VALUE   



In [153]: def func2():
   .....:     return 1 in ([] in 'a')
   .....: 

In [154]: dis.dis(func2)
  2           0 LOAD_CONST               1 (1)
              3 BUILD_LIST               0
              6 LOAD_CONST               2 ('a') 
              9 COMPARE_OP               6 (in)  # perform ([] in 'a'), which is 
                                                 # Incorrect, so it throws TypeError
             12 COMPARE_OP               6 (in)  # if no Error then 
                                                 # compare 1 with the result of ([] in 'a')
             15 RETURN_VALUE        

Whoa !! +1 Bu harika, çok teşekkürler! Gerçekten kullanışlı görünüyor, keşke bunu bilseydim! Bunun belgelerin neresinde olduğunu biliyor musunuz? Ben baktım ama bu önerilen bir şey bulamadık!
user541686

1
not: []yanlış olmakla []değil False, örneğin [] and anythingdöner [](değil False).
jfs

6
Check out @Mehrdad Python Çözücü ile kullanılmıştır ipython bu çıktıyı üretmek için.
Jeff Ferland

Dunno, Python'un hangi sürümü bunu oluşturdu, ancak Python 3.2 görünüşe göre yeni bir bayt koduna sahip: JUMP_IF_FALSE_OR_POP, bu, diziyi 13'ten 12'ye bir talimat kadar kısaltır. Harika cevap - teşekkürler !!
Dave

@Dave It's python 2.6.6 (iPython)
Ashwini Chaudhary

22

Python, zincirleme karşılaştırmalarla özel şeyler yapar.

Aşağıdakiler farklı şekilde değerlendirilir:

x > y > z   # in this case, if x > y evaluates to true, then
            # the value of y is being used to compare, again,
            # to z

(x > y) > z # the parenth form, on the other hand, will first
            # evaluate x > y. And, compare the evaluated result
            # with z, which can be "True > z" or "False > z"

Her iki durumda da, eğer ilk karşılaştırma ise False, ifadenin geri kalanına bakılmaz.

Özel durumunuz için,

1 in [] in 'a'   # this is false because 1 is not in []

(1 in []) in a   # this gives an error because we are
                 # essentially doing this: False in 'a'

1 in ([] in 'a') # this fails because you cannot do
                 # [] in 'a'

Ayrıca yukarıdaki ilk kuralı göstermek için bunlar True olarak değerlendirilen ifadelerdir.

1 in [1,2] in [4,[1,2]] # But "1 in [4,[1,2]]" is False

2 < 4 > 1               # and note "2 < 1" is also not true

Python operatörlerinin önceliği: http://docs.python.org/reference/expressions.html#summary


11

Belgelerden:

Karşılaştırmalar isteğe bağlı olarak zincirlenebilir, örneğin, x <y <= z, x <y ve y <= z'ye eşdeğerdir, tek fark, y'nin yalnızca bir kez değerlendirilmesidir (ancak her iki durumda da, x <y bulunduğunda z hiç değerlendirilmez yanlış olmak).

Bunun anlamı, hiçbir çağrışım yoktur x in y in z!

Aşağıdakiler eşdeğerdir:

1 in  []  in 'a'
# <=>
middle = []
#            False          not evaluated
result = (1 in middle) and (middle in 'a')


(1 in  []) in 'a'
# <=>
lhs = (1 in []) # False
result = lhs in 'a' # False in 'a' - TypeError


1 in  ([] in 'a')
# <=>
rhs = ([] in 'a') # TypeError
result = 1 in rhs

3

Kısa cevap, burada uzun olanı zaten birkaç kez ve mükemmel şekillerde verildiği için, boole ifadesinin kısa devre olması , bu, yanlışta doğru veya tersi bir değişiklik daha ileri değerlendirme ile gerçekleşemediğinde değerlendirmeyi durdurmuştur.

(bkz. http://en.wikipedia.org/wiki/Short-circuit_evaluation )

Cevap olarak biraz kısa olabilir (kelime anlamı yoktur), ancak belirtildiği gibi, diğer tüm açıklamalar burada zaten oldukça iyi yapılmıştır, ancak bu terimden bahsedilmeyi hak ettiğini düşündüm.

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.