Re: flow control and nested loops
On Sep 25, 12:01 pm, kj no.em...@please.post wrote: In Perl, one can label loops for finer flow control. For example: X: for my $x (@X) { Y: for my $y (@Y) { for my $z (@Z) { next X if test1($x, $y, $z); next Y if test2($x, $y, $z); frobnicate($x, $y, $z); } glortz($x, $y); } splat($x); } What's considered best practice in the Python world for this sort of situation? The only approach I can think of requires setting up indicator variables that must be set and tested individually; e.g. snip Whereas I find the Perl version reasonably readable, the Python one I find nearly incomprehensible. In fact, I'm not even sure that the Python version faithfully replicates what the Perl one is doing! Is there a better approach? The Perl syntax is elegant and readable. There is not a Python direct equivalent, but then the situation doesn't come up often. For the outermost loop, a break or continue suffices. To exit multiple levels of loop, there a several choices including try/except, flags, and functions with returns. A try/except approach looks like this: class NextX(Exception):pass class NextY(Exception):pass for x in X: try: for y in Y: try: for z in Z: if test1(x,y,z): raise NextX if test2(x,y,z): raise NextY frobnicate(x,y,z) except NextY: pass except NextX: pass Another approach for exiting multiple levels of loops is wrap the inner calls in a function and return from them when needed: def f(x): for y in y: for z in Z: if test1(x,y,z): return frobnicate(x,y,z) for x in X: f(x) Or you can write a little state machine with flags and a single loop but that isn't very readable or satisfying. Raymond -- http://mail.python.org/mailman/listinfo/python-list
Re: flow control and nested loops
Raymond Hettinger: Another approach for exiting multiple levels of loops is wrap the inner calls in a function and return from them when needed: def f(x): for y in y: for z in Z: if test1(x,y,z): return frobnicate(x,y,z) for x in X: f(x) That's usual the solution I use for this problem, it's a little rough and it has some performance cost, but it's readable and simple. In PHP break and continue accept an optional numeric value (default is 1, 0 is of course ignored) which tells it how many nested enclosing structures are to be broken out of.: http://us2.php.net/manual/en/control-structures.break.php http://us2.php.net/manual/en/control-structures.continue.php That PHP design gives me shivers, it's horrid, bug-prone and fragile: for x in X: for y in Y: for z in Z: if test1(x, y, z): continue 3 if test2(x, y, z): continue 2 frobnicate(x, y, z) glortz(x, y) splat(x) A better solution is to add labels to Python (I hope this code is equivalent to the original Perl one), that can optionally be used by continue and break. This solution design is also used by D: label OUTER: for x in X: label INNER: for y in Y: for z in Z: if test1(x, y, z): continue OUTER if test2(x, y, z): continue INNER frobnicate(x, y, z) glortz(x, y) splat(x) Bye, bearophile -- http://mail.python.org/mailman/listinfo/python-list
flow control and nested loops
In Perl, one can label loops for finer flow control. For example: X: for my $x (@X) { Y: for my $y (@Y) { for my $z (@Z) { next X if test1($x, $y, $z); next Y if test2($x, $y, $z); frobnicate($x, $y, $z); } glortz($x, $y); } splat($x); } What's considered best practice in the Python world for this sort of situation? The only approach I can think of requires setting up indicator variables that must be set and tested individually; e.g. for x in X: next_X = False for y in Y: next_Y = False for z in Z: if test1(x, y, z): next_X = True break if test2(x, y, z): next_Y = True break frobnicate(x, y, z) if next_X: break if next_Y: continue glortz(x, y) if next_X: continue splat(x) Whereas I find the Perl version reasonably readable, the Python one I find nearly incomprehensible. In fact, I'm not even sure that the Python version faithfully replicates what the Perl one is doing! Is there a better approach? TIA! kynn -- http://mail.python.org/mailman/listinfo/python-list
Re: flow control and nested loops
On Fri, Sep 25, 2009 at 3:01 PM, kj no.em...@please.post wrote: In Perl, one can label loops for finer flow control. For example: X: for my $x (@X) { Y: for my $y (@Y) { for my $z (@Z) { next X if test1($x, $y, $z); next Y if test2($x, $y, $z); frobnicate($x, $y, $z); } glortz($x, $y); } splat($x); } What's considered best practice in the Python world for this sort of situation? The only approach I can think of requires setting up indicator variables that must be set and tested individually; e.g. for x in X: next_X = False for y in Y: next_Y = False for z in Z: if test1(x, y, z): next_X = True break if test2(x, y, z): next_Y = True break frobnicate(x, y, z) if next_X: break if next_Y: continue glortz(x, y) if next_X: continue splat(x) Whereas I find the Perl version reasonably readable, the Python one I find nearly incomprehensible. In fact, I'm not even sure that the Python version faithfully replicates what the Perl one is doing! Is there a better approach? TIA! kynn snarkThe best approach would be to reorganize your code so you didn't have to do that./snark Seriously though, I find both the perl and python versions non-obvious. You have had to use constructs like this in practice? Generally, I would use flags in tricky nested loops just like you did, perhaps with some comments to clarify things. An alternative might be to use custom exceptions. Hopefully someone smarter than me will come along and show an even better approach. class NextX(Exception): pass class NextY(Exception): pass for x in X: try: for y in Y: try: for z in Z: if test1(x, y, z): raise NextX if test2(x, y, z): raise NextY frobnicate(x, y, z) except NextY: continue glortz(x, y) except NextX: continue splat(x) -- http://mail.python.org/mailman/listinfo/python-list
Re: flow control and nested loops
kj wrote: In Perl, one can label loops for finer flow control. For example: X: for my $x (@X) { Y: for my $y (@Y) { for my $z (@Z) { next X if test1($x, $y, $z); next Y if test2($x, $y, $z); frobnicate($x, $y, $z); } glortz($x, $y); } splat($x); } What's considered best practice in the Python world for this sort of situation? The only approach I can think of requires setting up indicator variables that must be set and tested individually; e.g. for x in X: next_X = False for y in Y: next_Y = False for z in Z: if test1(x, y, z): next_X = True break if test2(x, y, z): next_Y = True break frobnicate(x, y, z) if next_X: break if next_Y: continue glortz(x, y) if next_X: continue splat(x) Whereas I find the Perl version reasonably readable, the Python one I find nearly incomprehensible. In fact, I'm not even sure that the Python version faithfully replicates what the Perl one is doing! Is there a better approach? 1. Put inner loops in a function and return instead of break. 2. Put inner loops in try: for.. for if cond: raise Something # or do operation that raises exception if cond is true except e: whatever tjr -- http://mail.python.org/mailman/listinfo/python-list