Tính liên kết của “in” trong Python?


107

Tôi đang tạo trình phân tích cú pháp Python và điều này thực sự khiến tôi bối rối:

>>>  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

Chính xác thì "in" hoạt động như thế nào trong Python, liên quan đến tính liên kết, v.v.?

Tại sao không có hai biểu thức nào trong số này hoạt động giống nhau?


6
Có thể bạn đang gặp phải hành vi được mô tả ở đây: docs.python.org/reference/expressions.html#not-in , một hành vi cho phép bạn viết if a < b < c:và làm cho nó hoạt động một cách trực quan
millimoose 30/09/12

3
@millimoose: Vâng, tôi đoán là tôi chưa bao giờ nghĩ về inmột toán tử "so sánh". : \
user541686,

Câu trả lời:


123

1 in [] in 'a'được đánh giá là (1 in []) and ([] in 'a').

Vì điều kiện đầu tiên ( 1 in []) là False, toàn bộ điều kiện được đánh giá là False; ([] in 'a')không bao giờ thực sự được đánh giá, vì vậy không có lỗi nào được đưa ra.

Dưới đây là các định nghĩa câu lệnh:

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        

Ái chà!! +1 Thật tuyệt vời, cảm ơn rất nhiều! Nó trông thực sự tiện dụng, giá như tôi biết về nó! Bạn có biết điều này ở đâu trong tài liệu không? Tôi đã tìm nhưng không thể tìm thấy bất cứ điều gì gợi ý điều này!
user541686, 30/09/12

1
ghi chú: []là false, nhưng []không phải False, ví dụ, [] and anythingtrả về [](not False).
jfs

6
@Mehrdad Kiểm tra trình tháo gỡ Python được sử dụng với iPython để tạo đầu ra này.
Jeff Ferland

Không biết phiên bản Python nào đã tạo ra điều này, nhưng Python 3.2 rõ ràng có một mã bytecode mới: JUMP_IF_FALSE_OR_POP, rút ​​ngắn trình tự bằng một lệnh từ 13 xuống 12. Câu trả lời thú vị - cảm ơn !!
Dave

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

22

Python thực hiện những điều đặc biệt với các phép so sánh theo chuỗi.

Những điều sau được đánh giá khác nhau:

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"

Trong cả hai trường hợp, nếu là so sánh đầu tiên False, phần còn lại của câu lệnh sẽ không được xem xét.

Đối với trường hợp cụ thể của bạn,

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'

Ngoài ra, để chứng minh quy tắc đầu tiên ở trên, đây là các câu lệnh đánh giá thành True.

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

Mức độ phổ biến của toán tử python: http://docs.python.org/reference/expressions.html#summary


11

Từ tài liệu:

Các phép so sánh có thể được xâu chuỗi tùy ý, ví dụ: x <y <= z tương đương với x <y và y <= z, ngoại trừ việc y chỉ được đánh giá một lần (nhưng trong cả hai trường hợp, z không được đánh giá khi tìm thấy x <y sai).

Điều này có nghĩa là, không có sự kết hợp nào trong đó x in y in z!

Sau đây là tương đương:

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

Câu trả lời ngắn gọn, vì câu trả lời dài đã được đưa ra nhiều lần ở đây và theo những cách tuyệt vời, là biểu thức boolean bị ngắn mạch , điều này đã bị dừng đánh giá khi sự thay đổi true thành false hoặc ngược lại không thể xảy ra bằng cách đánh giá thêm.

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

Nó có thể hơi ngắn (không có ý định chơi chữ) như một câu trả lời, nhưng như đã đề cập, tất cả các giải thích khác đều đã được thực hiện khá tốt ở đây, nhưng tôi nghĩ thuật ngữ này đáng được đề cập.

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.