如何在Python中使用返回元组的函数的返回值作为while条件

14 投票
6 回答
3280 浏览
提问于 2025-04-17 19:51

我在找类似的东西,但没找到,所以就写出来了。

一些背景

我使用opencv从视频文件中提取帧。通常人们会用一个无尽的循环来做这件事,比如:

while (True):
    s, img = cv.read()

或者

for i in xrange(10000): #just a big number
    s, img = cv.read()

现在我想提取所有的帧,并在没有更多帧的时候退出循环。不过,我的python技能还不够强,无法做到我想做的事情。

我想知道的

read函数(或者说方法,我不知道在python里怎么称呼)返回一个元组:第一个元素表示操作是否成功,第二个元素表示返回的帧。我想在元组的第一个元素为假时退出循环。因为我有C语言的背景,我想也许这样可以实现:

while ((success, img = capture.read())[0]):
    #do sth with img

我以为这样在成功为假时会退出循环,但并没有成功。然后我想,也许这样可以:

while ((success, img = capture.read()).success):
    #do sth with img

结果也没有成功。我不想做类似这样的事情:

while(True):
    s, i = capture.read()
    if (s == False):
        break

我该如何在while中测试这个条件,而不是在一个if中,这样只有在成功时才会退出?

6 个回答

7

Python有一种替代的iter用法,它的第一个参数是一个函数,第二个参数是一个哨兵值,用来决定什么时候停止。

使用这种方式,你可以写出类似这样的代码:

for s,img in iter(cv.read, (False, None)):
    print img

不过,我还是怀疑这种方法是否比在if块里直接用break要好。

而且,它只能接受哨兵值作为返回的整体值,不能根据其中的一部分来决定停止条件(比如,不能根据元组的第一个值来判断)。虽然可以找到解决办法,但这样会让代码变得更加复杂:

>>> for s,img in itertools.takewhile(lambda x: x[0], iter(cv.read, None)):
    print img

它使用itertools.takewhile来判断返回的元组的第一个值是否等于False,从而决定何时停止。


完整的测试版本:

>>> class Capture(object):
    def __init__(self):
        self.L = iter([1,2,3,4,5])
    def read(self):
        try:
            img = self.L.next()
        except StopIteration:
            return (False,None)
        return True, img

>>> cv = Capture()
>>> for s,img in iter(cv.read, (False, None)):
    print img

1
2
3
4
5

>>> cv = Capture()
>>> for s,img in itertools.takewhile(lambda x: x[0], iter(cv.read, None)):
    print img


1
2
3
4
5
20

你可以写一个生成器函数。

def readframes(cv):
    while True:
        success, frame = cv.read()
        if success:
            yield frame
        else:
            return

这样你就可以用一个for循环来遍历这些帧。

for frame in readframes(cv):
    do_something_with_frame(frame)
7

想要更好地理解Python的编程风格,最好的办法就是暂时忘掉其他编程语言。

s = True
while s:
    s, i = capture.read()
    if s:
        do_some_stuff(i)

撰写回答