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

Hay*_*tuk 12 python conditional opencv while-loop python-2.7

我一直在寻找这样的东西,但我找不到它.

一些背景

我使用opencv从视频文件中检索帧.通常人们会在无限循环中这样做:

while (True):
    s, img = cv.read()
Run Code Online (Sandbox Code Playgroud)

要么

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

现在我想要检索所有帧并在没有更多帧时退出循环.但是我在python中的技能不够强,无法做我想做的事情.

我想知道什么

read函数(或方法,我不知道它们是如何在python中调用的)返回一个元组:第一个表示操作成功,第二个表示返回的帧.我想在元组的第一个元素为false时打破while循环.有C背景,我想也许这会起作用:

while ((success, img = capture.read())[0]):
    #do sth with img
Run Code Online (Sandbox Code Playgroud)

我认为这会在成功失败时打破循环.但事实并非如此.然后我想也许这会奏效:

while ((success, img = capture.read()).success):
    #do sth with img
Run Code Online (Sandbox Code Playgroud)

它也没用.我不想做类似的事情

while(True):
    s, i = capture.read()
    if (s == False):
        break
Run Code Online (Sandbox Code Playgroud)

如何测试条件while,而不是if成功中断?

小智 20

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

def readframes(cv):
    while True:
        success, frame = cv.read()
        if success:
            yield frame
        else:
            return
Run Code Online (Sandbox Code Playgroud)

这样你就可以用for循环遍历帧.

for frame in readframes(cv):
    do_something_with_frame(frame)
Run Code Online (Sandbox Code Playgroud)

  • @HayriUğurKoltuk:所以用"return"打破无限循环是可以的,但不能用"break"打破?为什么? (2认同)

orn*_*one 7

思考pythonic的最佳方式是忘记其他语言

s = True
while s:
    s, i = capture.read()
    if s:
        do_some_stuff(i)
Run Code Online (Sandbox Code Playgroud)

  • 就个人而言,我更喜欢OP的代码(`while True`和`break`),特别是如果在`if s`中有一些非常重要的代码.我发现一眼就能轻松掌握.但是,这只是个人偏好. (16认同)

ovg*_*vin 7

Python有一个替代iter签名,它将函数作为第一个参数,并将sentinel确定为第二个停止条件.

使用它,你可以得到这样的东西:

for s,img in iter(cv.read, (False, None)):
    print img
Run Code Online (Sandbox Code Playgroud)

不过,我怀疑它是不是只是普通的更好breakif块.

此外,它只接受sentinel作为整体返回值,并且不能基于它的某些部分停止条件(例如,在元组的第一个值上).这可以解决方法,但会使代码更加模糊:

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

它用于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
Run Code Online (Sandbox Code Playgroud)