Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python';短路?_Python - Fatal编程技术网

Python';短路?

Python';短路?,python,Python,如果我这样做: result = reduce(operator.and_, [False] * 1000) 它会在第一个结果之后停止吗?(因为False&anything==False) 同样地: result = reduce(operator.or_, [True] * 1000) 没有。在这种情况下,您的选择是和 可以用 result = all([False] * 1000) result = any([True] * 1000) 哪一个会短路 计时结果显示了差异: In [1]

如果我这样做:

result = reduce(operator.and_, [False] * 1000)
它会在第一个结果之后停止吗?(因为
False&anything==False

同样地:

result = reduce(operator.or_, [True] * 1000)

没有。在这种情况下,您的选择是和

可以用

result = all([False] * 1000)
result = any([True] * 1000)
哪一个会短路

计时结果显示了差异:

In [1]: import operator

In [2]: timeit result = reduce(operator.and_, [False] * 1000)
10000 loops, best of 3: 113 us per loop

In [3]: timeit result = all([False] * 1000)
100000 loops, best of 3: 5.59 us per loop

In [4]: timeit result = reduce(operator.or_, [True] * 1000)
10000 loops, best of 3: 113 us per loop

In [5]: timeit result = any([True] * 1000)
100000 loops, best of 3: 5.49 us per loop
reduce()不仅不会短路,而且不可能对所有要减少的项短路,因为它一次只考虑两个项。此外,它不知道在什么条件下使用的功能短路。(如果函数可以有一个属性来指示它们开始短路的值,这将是一件好事,reduce()随后可以识别和使用,但它们没有。)

很可能(请参阅)另一种reduce实现会做得很好

这个想法对我来说非常有效,使设计更加透明

def ipairs(seq):
    prev = None
    for item in seq:
        if prev is not None:
            yield (prev, item)
        prev = item

def iapply(seq, func):
    for a, b in ipairs(seq):
        yield func(a, b)

def satisfy(seq, cond):
    return all(iapply(seq, cond))

def is_uniform(seq):
    return satisfy(seq, lambda a, b: a == b)

正如您看到的,reduce被分解为iapply请记住,短路评估并不总是您想要的。因此,“修复”减少到短路将是一个错误。例如,在django中处理表单列表时,我最近不得不将all()的用法改为reduce():我想报告任何is_valid()问题,不仅仅是第一个。

我有一个相关的用例,我想要一个不同于
任何
所有
的行为,但相当于一个循环
。解决方案是使用
过滤器
,而不是
减少

any
返回布尔值,而
返回最后一个计算为
True
的对象

>>> any(['', 'a'])
True
>>> any(['', ''])
False
>>> any([0, 1])
True
>>> any([0, 0])
False
>>> '' or 'a'
'a'
>>> '' or ''
''
>>> 0 or 1
1
>>> 0 or 0
0
返回最后一个计算为
True的对象

>>> any(['', 'a'])
True
>>> any(['', ''])
False
>>> any([0, 1])
True
>>> any([0, 0])
False
>>> '' or 'a'
'a'
>>> '' or ''
''
>>> 0 or 1
1
>>> 0 or 0
0
reduce(operator.or,xs)
不会短路,但python3中的
next(filter(bool,xs))
或python2中的
next(itertools.ifilter(bool,xs))
会短路。这不是因为
filter
短路,而是因为返回的迭代器是惰性的,只会在需要时进行计算。通过使用
next
我们只要求满足筛选条件的第一个元素

>>> def maybenext(iter, onstopiter=False):
...     try: return  next(iter)
...     except StopIteration: return onstopiter
...     
>>> 
>>> maybenext(filter(bool, ['', 'a']))
'a'
>>> maybenext(filter(bool, ['', '']))
False
>>> maybenext(filter(bool, [0, 1]))
1
>>> maybenext(filter(bool, [0, 0]))
False
结果不如
any
快,但足够接近

>>> %timeit maybenext(filter(bool, [1] * 1000))
2.48 µs ± 91.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit any([1] * 1000)
2.26 µs ± 90.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit reduce(operator.or_, [1] * 1000)
47.3 µs ± 1.75 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

下面是一个可能的延迟reduce实现:

from itertools import accumulate

def lazy_reduce(pred, reducer, it, initial=None):
    accum = accumulate(it, reducer, initial=initial)
    last = None
    for item in accum:
        last = item
        if pred(item):
            return item
    return last
这应该像reduce一样工作,但会短接
pred

from operator import add
from itertools import count
res = short_reduce(lambda x: x > 20, add, count(1,8)) # 27

你说得对
any()
all()
似乎正是我所需要的(而且可能更清晰)。您是如何进行计时的?我正在使用
ipython
及其
timeit
命令。但是Python有一个timeit模块。因此,您可以从命令行执行
python-mtimeit“result=any([True]*10)”
计时。它可以使用一个关键字参数作为短路条件,其他内置函数做:reduce(operator.or,mylist,key=lambda x::x<0)这就是Lisp用户如此喜欢Lisp的原因——因为所有函数都是数据,它(原则上)是可以进行这种检测。