2013-03-21 8 views
12

Ich war auf der Suche nach so etwas, aber ich konnte nicht finden, so hier geht es.So verwenden Sie den Rückgabewert einer Funktion als Bedingung while das Tupel in Python zurückgibt

Einige Hintergrund

Ich benutze opencv Frames aus einer Videodatei abgerufen werden. Normalerweise tun es die Menschen in einer Endlosschleife wie:

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

oder

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

jetzt will ich alle Frames abzurufen und die Schleife beendet, wenn es keine weiteren Frames. Allerdings sind meine Fähigkeiten in Python nicht stark genug, um das zu tun, was ich tun möchte.

Was ich

read Funktion wissen möchten (oder eine Methode, ich weiß nicht, wie sie in Python genannt) gibt ein Tupel: erste Erfolg der Operation darstellt, und der zweite stellt den Rahmen zurück . Ich möchte die while-Schleife unterbrechen, wenn das erste Element des Tupels falsch ist. Mit einem C-Hintergrund dachte ich, das würde vielleicht funktionieren:

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

Ich dachte, dies wird die Schleife brechen, wenn der Erfolg falsch ist. Aber es tat es nicht. Dann dachte ich, das wird vielleicht funktionieren:

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

es hat auch nicht funktioniert. Ich will nicht so etwas wie

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

Wie testen in while den Zustand kann tun, nicht in einem if die, wenn sie erfolgreich bricht?

+3

Jeder Grund, warum Sie nicht die letzte Sache machen wollen (welche IMO ist die richtige Weise)? – RedBaron

+1

Ich bin mit @RedBaron auf diesem. Ich denke, dein letzter Auszug ist bei weitem der klarste. – NPE

+1

Ich denke, Bedingung von "while" sollte die Schleifenbedingung sein. –

Antwort

7

der beste Weg, pythonic zu denken ist, andere Sprachen

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

danke, fügte das 'if s:' – ornoone

+16

Persönlich, bevorzuge ich die OP-Code ('während True' und' break'), vor allem, wenn es eine nicht-triviale Menge an Code innerhalb dieser ' wenn s' ist. Ich finde es etwas leichter auf einen Blick zu erfassen. Dies ist jedoch nur eine persönliche Präferenz. – NPE

1

Dies sollte

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

Natürlich

zu vergessen, arbeiten Sie nicht in der Lage sein, den Rahmen auf diese Weise den Zugriff auf !!

Es gibt eine andere Art und Weise

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

Was natürlich ist seit langer ish Art zu sagen,

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

Welche (aus irgendeinem Grund) Sie wollen nicht

+0

Wenn das Lesen eine Funktion ist, wird es wahrscheinlich abstürzen, da Sie es nicht nennen – ornoone

+0

sorry ...verpasst, dass – RedBaron

+0

"Welche (aus irgendeinem Grund) Sie nicht tun möchten" Ich bevorzuge Überprüfung der While-Bedingung in 'while' selbst, nicht woanders. Ich denke, deshalb haben wir eine Bedingung nach 'while' Schlüsselwort. aber wenn in Python der richtige Weg ist, 'if' innerhalb einer endlosen Schleife zu benutzen, dann habe ich Angst, dass ich es benutzen muss. Ich fühle mich einfach nicht richtig ... –

0

zu tun Sie können nicht tun, was Sie in Python fragen (es sei denn, es gibt Hacks, die ich nicht kenne).

was die Zeile:

s, i = capture.read() 

durch Auspacken eines Tupels zuweist 2 separate Variablen tut, gibt einfach keine Möglichkeit, ist Python zu sagen, dass Sie die erste zugeordnete Variable wollen.
Es ist auch illegal in Python innerhalb einer , for oder while Bedingung Anweisung zuweisen.

das einzige, was man tun könnte, wäre:

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

was bedeuten würde, die Bilddaten verlieren.
Kurz gesagt, das Entpacken von Tupeln ist eigentlich ziemlich sexy, es gibt keinen Grund, die Funktionalität, die es bietet, nicht zu nutzen!

0

Hier ist eine Lösung auf, wer Schleife mit Hilfe der Funktion brechen Tupel zurückgeben.

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

Jetzt wird Ihr Code wie folgt aussehen:

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

Python eine alternative iter signature hat, die die Stoppbedingung als die zweite Bestimmungsfunktion als erstes Argument und Sentinel nimmt.

es verwenden, können Sie mit so etwas wie dies oben kommen kann:

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

Dennoch zweifle ich, ob es besser ist, als einfach nur break im if Block.

Außerdem akzeptiert es nur Sentinel als den gesamten zurückgegebenen Wert und kann die Basis-Stopp-Bedingung nicht auf einen Teil davon setzen (z. B. auf den ersten Wert des Tupels). Dies kann Abhilfe, aber der Code noch verschleierten machen:

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

Es verwendet itertools.takewhile zu bestimmen, wann der erste Wert des zurückgegebenen Tupel False entspricht.


Vollversion zum Testen:

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

scheinbar klar, wenn - Pause ist ein bisschen besser lesbar :) –

+0

@ HayriUðurKoltuk Ja, auf jeden Fall. Ich würde mit einem einfachen 'if-brake' gehen. – ovgolovin

20

Sie könnten eine Generatorfunktion schreiben.

Auf diese Weise können Sie die Frames mit einer for-Schleife durchlaufen.

for frame in readframes(cv): 
    do_something_with_frame(frame) 
+0

das sieht auf den ersten Blick ordentlich aus :) –

+2

@ HayriUðurKoltuk: Also ist es ok die Endlosschleife mit 'return' zu brechen, aber nicht mit' break'? Warum? – WolframH

+0

schließlich fing ich an zu denken, dass beide jetzt in Ordnung sind. Der Grund, warum ich das mochte, ist die Verwendung von 'Yield'. im zweiten Codefragment sieht die for-Schleife gut aus und ist gut lesbar –

Verwandte Themen