Python bitand (&) vs and

2020-04-16 03:22发布

问题:

Hi all I have this part of code:

for line in response.body.split("\n"):
    if line != "": 
        opg = int(line.split(" ")[2])
        opc = int(line.split(" ")[3])
        value = int(line.split(" ")[5])
        if opg==160 & opc==129:
            ret['success'] = "valore: %s" % (value)
            self.write(tornado.escape.json_encode(ret))

I have a series if line of type

1362581670        2459546910990453036    156     0     30      0

I want to take only the line where the third and fourth element are respectively 160 and 129. This code doesn't work. Do I have to do some casting? I think opg==160 is working to campare int with int...

回答1:

You got confused with the operators; and is the correct boolean test, & is a binary bitwise operator instead:

if opg == 160 and opc == 129:

As a numeric operator, the & operator has a higher precedence than comparison operators, while the boolean operators have a lower precedence. The expression opg == 160 & opc == 129 is thus interpreted as opg == (160 & opc) == 129 instead, which is probably not what you wanted.

You can simplify your code somewhat:

for line in response.body.splitlines():
    if line:
        line = map(int, line.split())
        opg, opc, value = line[2], line[3], line[5]
        if opg == 160 and opc == 129:
            ret['success'] = "valore: %s" % (value)
            self.write(tornado.escape.json_encode(ret))


回答2:

Just use line.split() instead of line.split(" "). That way it handles any type of whitespace. If those aren't just spaces, you'll get some weird results, which may be what's happening.



回答3:

& is a bitwise operation. You probably want and. With integers, you might not think that it would make a difference

>>> True & False
False
>>> True & True
True
>>> False & False
False

However, note that & and and have different priorities.

>>> opc,opg = 160,129
>>> opc == 160 & opg == 129
False
>>> opc == 160 and opg == 129
True

Basically, & binds tighter than ==, so a == b & c == d is parsed as a == ( b & c) == d rather than (a == b) & (c == d) like you wanted.

>>> def func1():
...     opc,opg = 160,129
...     opc == 160 & opg == 129
... 
>>> def func2():
...     opc,opg = 160,129
...     opc == 160 and opg == 129
... 
>>> import dis
>>> dis.dis(func1)
  2           0 LOAD_CONST               3 ((160, 129))
              3 UNPACK_SEQUENCE          2
              6 STORE_FAST               0 (opc)
              9 STORE_FAST               1 (opg)

  3          12 LOAD_FAST                0 (opc)
             15 LOAD_CONST               1 (160)
             18 LOAD_FAST                1 (opg)
             21 BINARY_AND          
             22 DUP_TOP             
             23 ROT_THREE           
             24 COMPARE_OP               2 (==)
             27 JUMP_IF_FALSE_OR_POP    39
             30 LOAD_CONST               2 (129)
             33 COMPARE_OP               2 (==)
             36 JUMP_FORWARD             2 (to 41)
        >>   39 ROT_TWO             
             40 POP_TOP             
        >>   41 POP_TOP             
             42 LOAD_CONST               0 (None)
             45 RETURN_VALUE        
>>> dis.dis(func2)
  2           0 LOAD_CONST               3 ((160, 129))
              3 UNPACK_SEQUENCE          2
              6 STORE_FAST               0 (opc)
              9 STORE_FAST               1 (opg)

  3          12 LOAD_FAST                0 (opc)
             15 LOAD_CONST               1 (160)
             18 COMPARE_OP               2 (==)
             21 JUMP_IF_FALSE_OR_POP    33
             24 LOAD_FAST                1 (opg)
             27 LOAD_CONST               2 (129)
             30 COMPARE_OP               2 (==)
        >>   33 POP_TOP             
             34 LOAD_CONST               0 (None)
             37 RETURN_VALUE        

As pointed out by Hoopdady, you also aren't splitting your string correctly. line.split() or line.split(None) will split on consecutive runs of whitespace.