为什么运算符模块缺少`和`以及`或`?

时间:2013-10-04 16:43:07

标签: python module operator-keyword

operator模块可以轻松避免不必要的函数和lambda 在这种情况下:

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

好吧,现在我需要做i1 and i2,但令我惊讶的是,我在操作员模块中找不到and!这同样适用于or!我知道,and不完全是运算符,它是关键字,但是not,还有is甚至{{1所有关键字都包括在内。

那故事是什么?他们为什么失踪?

4 个答案:

答案 0 :(得分:9)

因为您无法将布尔运算符转换为python函数。函数总是评估它们的参数,而布尔运算符则不会。将andor添加到运算符模块还需要添加一种特殊类型的函数(如lisp“宏”),以按需评估其参数。显然,这不是python设计师想要的东西。考虑:

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

你不能以功能形式写这个。尝试

  if operator.xyz(obj is not None, obj.is_valid()) 
如果obj实际为None,则

将失败。

答案 1 :(得分:3)

你可以自己编写这些,但你需要为第二个参数传递一个函数(例如lambda),以防止它在调用时被评估,假设通常的短路行为对你很重要。 / p>

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

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

用法:

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

答案 2 :(得分:1)

没有operator.and的原因是and是关键字,因此它是SyntaxError

正如tgh435所解释的那样,and中没有重命名operator函数的原因是它会产生误导:函数调用总是评估其操作数,但and运算符不会。 (对于其他一致且简单的规则,这也是一个例外。)


在您的情况下,看起来您根本不关心短路,因此可以轻松构建您自己的版本:

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

或者,如果您只使用一次,甚至内联:

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

在某些情况下,值得查看all(以及orany)。它实际上被短路and扩展到任意操作数。当然,它具有与operator函数不同的API,采用单个可迭代的操作数而不是两个单独的操作数。它的短路方式也不同;它只是停止迭代迭代,这只有在你设置的时候才有用,所以iterable只是根据需要进行评估。因此,它通常不能作为替代品使用 - 但如果您稍微重构代码,它有时是可用的。

答案 3 :(得分:0)

Python的WKWebViewclass YouTubeVideoPlayerVC: UIViewController { @IBOutlet weak var videoPlayerView: WKWebView! var videoURL:URL! // has the form "https://www.youtube.com/embed/videoID" var didLoadVideo = false override func viewDidLoad() { super.viewDidLoad() videoPlayerView.configuration.mediaTypesRequiringUserActionForPlayback = [] } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // Size of the webView is used to size the YT player frame in the JS code // and the size of the webView is only known in `viewDidLayoutSubviews`, // however, this function is called again once the HTML is loaded, so need // to store a bool indicating whether the HTML has already been loaded once if !didLoadVideo { videoPlayerView.loadHTMLString(embedVideoHtml, baseURL: nil) didLoadVideo = true } } var embedVideoHtml:String { return """ <!DOCTYPE html> <html> <body> <!-- 1. The <iframe> (and video player) will replace this <div> tag. --> <div id="player"></div> <script> var tag = document.createElement('script'); tag.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); var player; function onYouTubeIframeAPIReady() { player = new YT.Player('player', { height: '\(videoPlayerView.frame.height)', width: '\(videoPlayerView.frame.width)', videoId: '\(videoURL.lastPathComponent)', events: { 'onReady': onPlayerReady } }); } function onPlayerReady(event) { event.target.playVideo(); } </script> </body> </html> """ } } 语法无法直接映射到函数。这些语法是惰性求值的:如果表达式左侧部分的结果允许知道整个表达式的值,则跳过右侧部分。由于它们引入了流量控制,因此无法使用操作员再现它们的行为。 为了减少混淆,python选择不提供这些方法。

georg给出了and懒惰很重要的一个很好的例子:

or

现在,如果您不需要延迟评估,可以使用abarnert的答案实现:

and

用法:

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

如果您需要延迟评估,可以使用kindall的答案实施:

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

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

用法:

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

注意: 如评论中所述,函数def func_or(val1, fval2): return val1 or fval2() def func_and(val1, fval2): return val1 and fval2() >>> func_or(False, lambda: True) >>> func_and(True, lambda: False) 对应于按位运算符operator.and_operator.or_。请参阅:https://docs.python.org/3/library/operator.html#mapping-operators-to-functions

请注意,未使用名称&|operators.andoperators.or是Python关键字,因此会出现语法错误。