【问题标题】:How to use return value of a function as condition of while that returns tuple in python如何使用函数的返回值作为在python中返回元组的while条件
【发布时间】:2013-03-10 15:44:46
【问题描述】:

我一直在寻找类似的东西,但我找不到,所以就在这里。

一些背景

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

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

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

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

我想知道的

read函数(或者方法,我不知道在python中是怎么调用的)返回一个元组:第一个代表操作成功,第二个代表返回的帧。当元组的第一个元素为假时,我想打破 while 循环。有 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 中的条件?

【问题讨论】:

  • 有什么理由不想做最后一件事(哪种 IMO 是正确的方法)?
  • 我支持@RedBaron。我认为你的最后一段摘录是迄今为止最清晰的。
  • 我认为while的条件应该是循环条件。
  • 值得注意的是,在python中,不能在while或if语句的条件下进行赋值。
  • 顺便说一句:人们while(True),他们写while True。不需要括号,它们只会增加表达式的复杂性。

标签: python python-2.7 opencv while-loop conditional


【解决方案1】:

思考pythonic的最好方法是忘记其他语言

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

【讨论】:

  • 就我个人而言,我更喜欢 OP 的代码(while Truebreak),尤其是在 if s 中包含大量代码的情况下。我发现一目了然更容易掌握。不过,这只是个人喜好。
【解决方案2】:

这应该可以工作

while capture.read()[0]: 
    #do something

当然你不能那样访问框架!!

还有一种方法

s,v = capture.read()
while s:
    #Do sth
    s,v = capture.read()

这当然是一种冗长的说法

while True: 
    s,v = capture.read()
    if not s: 
        break

你不想做什么(出于某种原因)

【讨论】:

  • 如果 read 是一个函数,它可能会崩溃,因为你不调用它
  • “你不想做什么(出于某种原因)”我更喜欢检查 while 本身的 while 条件,而不是其他地方。我认为这就是为什么我们在while 关键字之后有一个条件。但是如果在python中正确的方法是在无限循环中使用if,那么恐怕我将不得不使用它。我只是觉得不对劲......
  • 啊!但你的 if is 在 while 内。无论如何,您可以使用我的第二个选项,或者使用 ornoone 的答案。
【解决方案3】:

你不能在 python 中做你要求的事情(除非有我不知道的黑客)。

什么行:

s, i = capture.read()

正在做的是通过解包一个元组来分配 2 个单独的变量,没有办法告诉 python 你想要第一个分配的变量。
在 python 中,在 ifforwhile 条件语句中赋值也是非法的。

你唯一能做的就是:

if(capture.read()[0]):

这意味着您会丢失图像数据。
简而言之,解包元组实际上非常性感,没有理由不利用它提供的功能!

【讨论】:

    【解决方案4】:

    这是一个使用返回元组的函数来打破循环的解决方案。

    >>> def read(a):
    ...     if a == 0:
    ...         return (False, a+1)
    ...     return (True, a-1)
    ... 
    >>> read(5)
    (True, 4)
    >>> read(0)
    (False, 1)
    >>> a = True
    >>> i = 5
    >>> while(a):
    ...     a, i = read(i)
    ...     if a:
    ...         print 'working'
    ...         
    ...     
    ... 
    working
    working
    working
    working
    working
    >>> 
    

    现在您的代码将如下所示:

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

    【讨论】:

      【解决方案5】:

      Python 有一个alternative iter signature,它将函数作为第一个参数,将确定停止条件的哨兵作为第二个参数。

      使用它,你可以想出这样的东西:

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

      不过,我怀疑它是否比 if 块中的普通 break 更好。

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

      >>> 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
      

      【讨论】:

      • @HayriUğurKoltuk 是的,当然。我会选择普通的if-brake
      【解决方案6】:

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

      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)
      

      【讨论】:

      • 第一眼看上去很整洁 :)
      • @HayriUğurKoltuk:所以可以用return 打破无限循环,但不能用break?为什么?
      • 毕竟我现在开始认为两者都可以。我喜欢这个的原因是使用yield。在第二个代码片段中,for 循环看起来不错且非常易读
      • @WolframH:你说得很好。生成器 与在 while 循环中使用 break 基本相同。它的效率也有点低。
      猜你喜欢
      • 2017-04-16
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      • 2019-02-01
      • 1970-01-01
      • 2016-01-30
      • 1970-01-01
      • 2013-11-09
      相关资源
      最近更新 更多