Python 为什么';t all()是否在第一个False元素上停止?

Python 为什么';t all()是否在第一个False元素上停止?,python,Python,从中,all相当于: def all(iterable): for element in iterable: if not element: return False return True 那么为什么我会得到这个输出: # expecting: False $ python -c "print( all( (isinstance('foo', int), int('foo')) ) )" Traceback (most recent

从中,
all
相当于:

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True
那么为什么我会得到这个输出:

# expecting: False

$ python -c "print( all( (isinstance('foo', int), int('foo')) ) )"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'foo'

参数在调用函数之前进行求值。在本例中,首先必须创建传递给
all
的元组

all
从未有机会检查它们,在此之前引发了异常

>>> int('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'foo'
>>int('foo')
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ValueError:基数为10的int()的文本无效:“foo”
获得您想要的行为的一种(相当丑陋)方法是通过lambdas:

all(f() for f in (lambda: isinstance('foo', int), lambda: int('foo')))

如果在第一个
False
条件后停止求值的目的是专门执行类型检查,那么类似的方法会更好:

if not isinstance(other, MyClass):
    return False
else:
    return all((self.attr1 == other.attr2,
                self.attr2 == other.attr2)) # etc.

简化版本来自:


你对
所有
的直觉是正确的;您只需要稍微努力一点就可以设置一个惰性序列。例如:

def lazy():
    yield isinstance("foo", int)   # False
    yield int("foo")               # raises an error, but we won't get here

>>> all(lazy())
False
>>> list(lazy())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in lazy
ValueError: invalid literal for int() with base 10: 'foo'
def lazy():
收益率存在(“foo”,int)#错误
yield int(“foo”)#引发了一个错误,但我们不会在这里看到
>>>全部(lazy())
假的
>>>列表(lazy())
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第3行,格式为
ValueError:基数为10的int()的文本无效:“foo”


int('foo')
将在调用
all
之前进行评估。欢迎使用严格的评估机制。也许你更喜欢和Haskell一起工作。了解你想用这段代码解决什么问题可能会有所帮助。我认为可能有更好的方法来实现它。@Marcin使用生成器,您也可以在python中实现OP想要的;-)@但是,除非使用
ast
,否则无法以编程方式创建它。这不是一个真正的解决方案。这是获得我想要的模式的唯一方法吗:
if condition1。。。如果条件2。。。elif条件3…
?如果条件1为False,则仅计算条件2。我只希望在条件2为False时计算条件3,以此类推。
cond1或cond2或cond3
。但是你发布的内容还有别的作用。困惑。@JaceBrowning,你上面的评论与你的问题冲突。对于使用
all()
的方式延迟检测False,应该是
isinstance('foo',int)和int('foo')
@dansalmo,我的困惑是我认为
all((f1(),f2(),f3())
正在创建一个将被延迟计算的生成器。请不要将此作为答案发布,但是更新你的question@catchmeifyoutry如果用户发现了解决方案,回答他们自己的问题是完全可以接受的。@catchmeifyoutry,我编辑了措辞,使其听起来更像一个答案。@DanielRoseman我同意@(那好吧;)我以为你在回答Karoly时试图澄清你的问题。顺便说一句,您可以将解决方案简化为:
返回isinstance(other,MyClass)和all(…)
,如果isinstance测试失败,则会中断评估。用户回答自己的问题通常是可以接受的,但问题的格式应该正确。这是同一用户询问x并回答y的情况。最初的问题本应与这个答案更直接相关。请看,这与OP的问题并不完全相同,因为您将
isinstance
应用于
lazy
生成的所有元素。这只是一个例子的结果。@dansalmo但这不是练习的全部要点吗,
all
缩短了评估?我的意思是,是的,我会将
isinstance
应用于
lazy
返回的所有元素,除了
all
在将引发的项目有机会引发之前停止评估。OP正确地预期会发生短路,但在设置一个急切序列而不是惰性序列时出错。我认为您的第二行应该是
yield isintance(“foo”,int)
。然后,您可以在
all()
@jaceb中删除对
isinstance
的调用。很好,我现在已经按照您的建议编辑了答案。好处是对
all()
的调用现在与对
list()
的调用对称。缺点是,这似乎没有实际代码中使用或遇到的生成器表达式那么有意义。+1,当问题的最佳解决方案是丑陋的时,问题可能就是问题。
return isinstance(other, MyClass) and all((self.attr1 == other.attr2,
                                           self.attr2 == other.attr2)) # etc.
def lazy():
    yield isinstance("foo", int)   # False
    yield int("foo")               # raises an error, but we won't get here

>>> all(lazy())
False
>>> list(lazy())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in lazy
ValueError: invalid literal for int() with base 10: 'foo'