Why is operator module missing `and` and `or`?

馋奶兔 提交于 2019-12-02 04:43:15

问题


operator module makes it easy to avoid unnecessary functions and lambdas in situations like this:

import operator

def mytest(op, list1, list2):
    ok = [op(i1, i2) for i1, i2 in zip(list1, list2)]
    return all(ok)

mytest(operator.eq, [1, 2, 3], [1, 2, 3])         # True
mytest(operator.add, [-1, 2, -3], [1, -2, 33])    # False

Well, now I need to do i1 and i2, but to my surprise, I can't find and in the operator module! And the same applies to or! I know, and is not exactly operator, it's a keyword, but not, along with is and even del, are all keywords and all are included.

So what's the story? Why are they missing?


回答1:


Because you cannot convert boolean operators into python functions. Functions always evaluate their arguments, and boolean operators do not. Adding and and or to the operators module would also require adding a special kind of functions (like lisp "macros") that evaluate their arguments on demand. Obviously, this is not something python designers ever wanted. Consider:

if obj is not None and obj.is_valid():
    ....

you cannot write this in a functional form. An attempt like

  if operator.xyz(obj is not None, obj.is_valid()) 

will fail if obj is actually None.




回答2:


You can write these yourself, but you'll need to pass a function (e.g. lambda) for the second argument to prevent it from being evaluated at call time, assuming that the usual short-circuiting behavior is important to you.

def func_or(val1, fval2):
    return val1 or fval2()

def func_and(val1, fval2):
    return val1 and fval2()

Usage:

func_or(False, lambda: True)
func_and(True, lambda: False)



回答3:


The reason there's no operator.and is that and is a keyword, so that would be a SyntaxError.

As tgh435 explained, the reason there's no renamed and function in operator is that it would be misleading: a function call always evaluates its operands, but the and operator doesn't. (It would also be an exception to an otherwise consistent and simple rule.)


In your case, it looks like you don't actually care about short-circuiting at all, so can build your own version trivially:

def and_(a, b):
    return a and b

Or, if you're just using it once, even inline:

mytest(lambda a, b: a and b, [-1, 2, -3], [1, -2, 33])

In some cases, it's worth looking at all (and, for or, any). It is effectively short-circuited and expanded to arbitrary operands. Of course it has a different API than the operator functions, taking a single iterable of operands instead of two separate operands. And the way it short-circuits is different; it just stops iterating the iterable, which only helps if you've set things up so the iterable is only evaluating things as needed. So, it's usually not usable as a drop-in replacement—but it's sometimes usable if you refactor your code a bit.




回答4:


Python's and and or syntaxes cannot directly be mapped to functions. These syntaxes are lazy evaluated: If the result of the left part of the expression allows to know the value of the whole expression, the right part is skipped. Since they introduce flow control, their behavior cannot be reproduced using an operator. To reduce confusion, python have chosen to simply not provide these methods.

georg gives a good example of a situation where and laziness matters:

 if obj is not None and obj.is_valid():
     ...

Now, if you don't need lazy evaluation, you can use abarnert's answer implementation:

def and_(a, b):
    return a and b

def or_(a, b):
    return a or b

Usage:

>>> or_(False, True)
>>> and_(True, False)

If you need lazy evaluation, you can use kindall's answer implementation:

def func_or(val1, fval2):
    return val1 or fval2()

def func_and(val1, fval2):
    return val1 and fval2()

Usage:

>>> func_or(False, lambda: True)
>>> func_and(True, lambda: False)

Note: As mentioned in the comments, the functions operator.and_ and operator.or_ correspond to the bitwise operators & and |. See: https://docs.python.org/3/library/operator.html#mapping-operators-to-functions

Note that the names operators.and and operators.or aren't used: and and or are Python keywords so it would be a syntax error.



来源:https://stackoverflow.com/questions/19186564/why-is-operator-module-missing-and-and-or

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!