Is there a breaking flow control mechanism for modules?
Regardless of the context, I've found it cleaner to use flow control
statements, like break, continue, and return, to stop execution under
some condition and then leave the rest of my code at the smaller
indentation level. For example:
for i in range(5):
if i % 2:
print("odd: %s" % i)
continue
print("even: %s" % i)
This could be written with if-else for control flow:
for i in range(5):
if i % 2:
print("odd: %s" % i)
else:
print("even: %s" % i)
Or, for functions:
def f(arg):
if not arg:
return None
print("found something: %s" % arg)
return arg
vs:
def f(arg):
if not arg:
result = None
else:
print("found something: %s" % arg)
result = arg
return result
The more levels of indentation the harder it becomes to read.
However, with the breaking flow control statements, you can mitigate
the nesting levels somewhat. One nice thing is that when doing this
you can have your default behavior stay at the smallest indentation
level, so the logic is easier to read.
With modules I sometimes have code at the beginning to do some small
task if a certain condition is met, and otherwise execute the rest of
the module body. Here's my main use case:
"""some module"""
import sys
import importlib
import util # some utility module somewhere...
if __name__ == "__main__":
name = util.get_module_name(sys.modules[__name__])
module = importlib.import_module(name)
sys.modules[__name__] = module
else:
# do my normal stuff at 1 indentation level
I would rather have something like this:
"""some module"""
import sys
import importlib
import util # some utility module somewhere...
if __name__ == "__main__":
name = util.get_module_name(sys.modules[__name__])
module = importlib.import_module(name)
sys.modules[__name__] = module
break
# do my normal stuff at 0 indentation level
So, any thoughts? Thanks.
-eric
p.s. I might just handle this with a PEP 302 import hook regardless,
but it would still be nice to know if there is a better solution than
basically indenting my entire module.
To me, too -- too bad it doesn't work:
c:\temp>\python32\python early_abort.py
File "early_abort.py", line 7
return
^
SyntaxError: 'return' outside function
~Ethan~
The answer would depend on exactly what "normal stuff" you expect your
module to do if it's not being run as a script (which is what your
`__name__ == '__main__'` check tests for). A typical module will define
it's appropriate attributes, functions, classes, and so on at module
scope. It will then end with a test to see if it's being run as a
script, and then do the appropriate thing. This allows modules to be
imported separately from being executed as scripts.
Your sample code makes it hard to understand the use case, especially
since if you want this hypothetical "module break" to stop executing the
module, then your `__name__ == '__main__'` test basically does nothing
useful (it fiddles with some modules -- especially since it appears to
be they very module that is being executed -- and then quits).
At a more general level, the idea of a "module break" doesn't make much
sense. Modules are just collections of things; they can include some
direct code, but typically consist of mostly definitions. Modules can
interact with each other, be called recursively, etc., and so at an
arbitrary point saying, "break out of this module" doesn't have a great
deal of meaning.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
There is _never_ no hope left. Remember.
-- Louis Wu
Nor should it. There's nothing to return out of.
> When you want to stop execution of a statement body early, for flow
> control, there is a variety ways you can go, depending on the context.
> Loops have break and continue. Functions have return. Generators
> have yield (which temporarily stops execution). Exceptions sort of
> work for everything, but have to be caught by a surrounding scope, and
> are not necessarily meant for general flow control.
>
> Is there a breaking flow control mechanism for modules?
Since your nominated use case is only to do it when ‘__name__ ==
'__main__'’, you could call ‘sys.exit()’.
> With modules I sometimes have code at the beginning to do some small
> task if a certain condition is met, and otherwise execute the rest of
> the module body.
I don't see how your use case needs to skip executing the rest of the
module code.
> Here's my main use case:
>
> """some module"""
>
> import sys
> import importlib
> import util # some utility module somewhere...
>
> if __name__ == "__main__":
> name = util.get_module_name(sys.modules[__name__])
> module = importlib.import_module(name)
> sys.modules[__name__] = module
> else:
> # do my normal stuff at 1 indentation level
What “normal stuff” is the module doing that shouldn't be done when the
module is ‘__main__’? I can't see what the use case is for.
As you're no doubt aware, the normal pattern is to execute all the
“normal stuff” for a module unconditionally, which creates all the
objects in the module namespace (its imports, classes, functions, and
other attributes) without side effects; then check if the module is
‘__main__’ at the *end*.
So you'll probably need to be more specific about why your use case
differs from that.
--
\ “Pinky, are you pondering what I'm pondering?” “I think so, |
`\ Brain, but if the plural of mouse is mice, wouldn't the plural |
_o__) of spouse be spice?” —_Pinky and The Brain_ |
Ben Finney
Perhaps we have a misunderstanding then. The contents of a module
file are the body of the module definition. Like the body of any
other complex statement, that body is going to get executed [1].
Some of the complex statements have keywords that let you break out of
that execution, like break and continue in loops. Some do not.
However, there is most certainly something out of which to return, the
execution of the module body.
That fact that the functionality is not there does not mean it has to
stay that way. It may just be that no one has thought to add it. I
don't agree that it's a bad idea. I have a use case. The alternative
is unappealing to me. That's how new features are born.
I apologize if my example was unclear. I kept it pretty simple. I
expect using __main__ was misleading. However, this is by no means
the only use case. In general it would be nice to do some checks up
front and decide whether or not to continue executing the module,
rather than waiting until the end to decide:
if condition_1:
...
return
if condition_2:
...
return
# now do my expensive module stuff
# finally handle being run as a script
if __name__ == "__main__":
...
The only ways that I know of to accomplish this currently is either by
putting everything inside if-else blocks, or raise some kind of
ImportBreak exception and catch it in an import hook. I would rather
not use either one. The more levels of indentation in a module, the
harder it is to follow. And exceptions really should not be involved
in execution flow control, but in the handling of abnormal situations
instead.
Considering that other complex statements have special flow control
statements, I don't see why modules shouldn't either.
-eric
[1] During import the module gets compiled and the result is exec'ed
in the context of the __dict__ of a new ModuleType object. That
module object is then placed in sys.modules and bound to the name you
have in the import statement in the module from which you issued that
statement. Remember, the module is executed once, when the import
statement is executed. That is when the module flow control would
happen.
> --
> Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
> San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
> There is _never_ no hope left. Remember.
> -- Louis Wu
> I apologize if my example was unclear. I kept it pretty simple.
That's a good goal, but unfortunately in this case it means the purpose
is opaque.
> In general it would be nice to do some checks up front and decide
> whether or not to continue executing the module, rather than waiting
> until the end to decide:
>
> if condition_1:
> ...
> return
> if condition_2:
> ...
> return
>
> # now do my expensive module stuff
I have never seen code that needs this, and can't imagine why the above
would be a good design for a module. Is there real code online somewhere
that we can see which serves as a real example for your use case?
--
\ “There is no reason anyone would want a computer in their |
`\ home.” —Ken Olson, president, chairman and founder of Digital |
_o__) Equipment Corp., 1977 |
Ben Finney
The best way I can think of is:
def expensive_stuff_1():
...
def expensive_stuff_2():
...
if not condition_1:
expensive_stuff_1()
if not condition_2:
expensive_stuff_2()
Depending on what exactly you're doing, this might make perfect sense,
or might be a useless indentation level of its own. If the expensive
stuff divides nicely into units, where each unit is governed by one
condition, it might work out well that way; you could use the same
functions to build your 'if __main__' section too.
ChrisA
Unfortunately not. Most of this line of thinking is the result of
looking at import functionality in different ways, including with
regards to the problem of modules getting imported twice (once as
__main__). I've been doing work on multi-file modules, custom module
objects, and custom import hooks lately, so I have been exploring a
lot of the import related features. The situation came up where I was
trying to actually apply some of that across a large package.
The use case I originally gave is the real-life one that got me
thinking about module flow control statements. However, the situation
that led me there is not particularly wide-spread. Keep in mind that
initially I was looking to see if there was something like return or
break for modules, and not asking that they be added. That "expensive
module stuff" example I gave was purely hypothetical, and I haven't
really seen real code like it either.
Like I said, my main motivation is to reduce my levels of indentation
somewhat. I was trying to see if I could apply a pattern I use in
functions and loops to modules. Things like "I have never seen..."
are really helpful to hear, by the way, so thanks!
-eric
> --
> \ “There is no reason anyone would want a computer in their |
> `\ home.” —Ken Olson, president, chairman and founder of Digital |
> _o__) Equipment Corp., 1977 |
> Ben Finney
One might argue that a module is not a statement.
| Some of the complex statements have keywords that let you break out of
| that execution, like break and continue in loops. Some do not.
| However, there is most certainly something out of which to return, the
| execution of the module body.
Ok...
| That fact that the functionality is not there does not mean it has to
| stay that way. It may just be that no one has thought to add it. I
| don't agree that it's a bad idea. I have a use case. The alternative
| is unappealing to me. That's how new features are born.
One litmus test may be whether such a statement buys you much.
You say you have a use case, but so far it seems rather vague to me.
Speaking for myself, my modules tend to be a heap of class or function
definitions (cheap - a linear parse of the file) and a few
as-simple-as-possible initialisations of any supporting global data
structures. Actual examples of global data structures are hard to find,
but of the few I make, here's one:
__seq = 0
__seqLock = allocate_lock()
def seq():
''' Allocate a new sequential number.
Useful for creating unique tokens.
'''
global __seq
global __seqLock
__seqLock.acquire()
__seq += 1
n = __seq
__seqLock.release()
return n
to support a free gimme-a-unique-number in other code:
from cs.misc import seq
...
n = seq()
| I apologize if my example was unclear. I kept it pretty simple.
Too simple, IMO. Please present a real module excerpt from your own code
where significant "not a class or function definition" code is executed
so we can see what ind of stuff you do that would benefit.
| I
| expect using __main__ was misleading. However, this is by no means
| the only use case. In general it would be nice to do some checks up
| front and decide whether or not to continue executing the module,
| rather than waiting until the end to decide:
|
| if condition_1:
| ...
| return
| if condition_2:
| ...
| return
|
| # now do my expensive module stuff
|
| # finally handle being run as a script
| if __name__ == "__main__":
| ...
I think many people don't think of a module as something "to execute".
Of course, it _is_ executed but for most modules the stuff executed is
unconditional and single pass class and function definitions, "constant"
definitions (such as the symbolic logging level of the logging module
etc).
All such stuff is usually unconditional (or trivially conditional, eg
"only define this on MacOSX" etc).
In my own case, the only counter example I can recall is stuff like a
main() function. In those cases my modules take the form:
import stuff ...
def main(argv):
xit = 0
... main program top level logic here ...
return xit
... classes, functions etc ...
if __name__ == __'main__':
sys.exit(main(sys.argv))
This keeps the top level logic at the top where it is easy to find.
That covers the case where running the module becomes a little utility
(typically a basic tool to manipulate an instance of whatever facility
the module provides). For the other common case in tension with this, to
run unit tests, we just call the unittests at the bottom or if both
modes make sense I tend to make main() accept a "selftest" argument
to run the unittests.
So my own code doesn't cry out for what you seem to be asking.
Please make it more clear what you're doing that I'm not.
| The only ways that I know of to accomplish this currently is either by
| putting everything inside if-else blocks, or raise some kind of
| ImportBreak exception and catch it in an import hook. I would rather
| not use either one. The more levels of indentation in a module, the
| harder it is to follow. And exceptions really should not be involved
| in execution flow control, but in the handling of abnormal situations
| instead.
|
| Considering that other complex statements have special flow control
| statements, I don't see why modules shouldn't either.
Basicly because, in my experience, an approach like havig a main()
function often covers it. Counter/other examples needed!
Cheers,
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
The major difference between a thing that might go wrong and a thing that
cannot possibly go wrong is that when a thing that cannot possibly go wrong
goes wrong, it usually turns out to be impossible to get at or repair.
- Douglas Adams
Watch out for that importing of the original script. Doing that has
many risks, only one of which is the problem of the two names.
In fact, any time you have mutual imports, you run a certain risk, if
the modules involved have any code that's not inside defs. It's not
well defined what order the initialisation happens, so you may wind up
calling code in another module that's not really there yet.
The module import tree should be strictly hierarchical, without cycles.
if you need stuff from the __main__, pass it to the other module,
don't let the other module peek back over your shoulder.
In the case of a module importing things from your script, the solution
is pretty simple. Move the needed code elsewhere, and import it both
from your script and from the other module.
DaveA
It's quite consistent on which control structures you can break out of
-- it's the looping ones.
> However, there is most certainly something out of which to return, the
> execution of the module body.
You return out of functions or methods. Not modules.
> I apologize if my example was unclear. I kept it pretty simple. I
> expect using __main__ was misleading. However, this is by no means
> the only use case. In general it would be nice to do some checks up
> front and decide whether or not to continue executing the module,
> rather than waiting until the end to decide:
>
> if condition_1:
> ...
> return
> if condition_2:
> ...
> return
>
> # now do my expensive module stuff
>
> # finally handle being run as a script
> if __name__ == "__main__":
> ...
>
> The only ways that I know of to accomplish this currently is either by
> putting everything inside if-else blocks, or raise some kind of
> ImportBreak exception and catch it in an import hook.
You're still not elucidating a very clear use case here. You want to do
some tests and then break out of the top-level execution of the module
if they happen. Just use `sys.exit`.
It's still not clear _why_ this is useful. As I said, the typical
behavior of a module is to define a lot of things, perhaps building up
some needed data structures, and then do the `__name__ == "__main__"`
test to see if it's being executed as a script, and then _do_ something.
So it's still not clear what tests you're trying to perform while
defining the contents of the module (but before executing it as a
script, should that be the case), and then exit.
The only situation where the execution of the contents of the module
might vary with top-level branching tests is for portability or version
reasons, say, checking `sys.platform` or `sys.version` and then doing
different things depending on their values. But these are easily
handled with if/else structures -- or, if that gets unwieldy, using a
lookup table -- and, at any rate, you're _not_ going to "break out of
the module" once you've done that, you're going to continue on
definition the non-(platform, version)-specific stuff, then test whether
it's being run as a script, and then do something.
The only case I can see for exiting out of a module early would be if
something exceptional happens that leads the module's internal logic to
conclude that it can't be used. But the solution there is
straightforward: Raise an exception.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
We have always been space travelers.
-- Carl Sagan, 1934-1996
If your sole goal here is to reduce clutter, then turn a repeated
if/elif/else case into a dictionary lookup where the keys are functions,
and execute the value. Even then, unless there are quite a lot of
cases, this may be overkill.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
I am not afraid / To be a lone Bohemian
-- Lamya
Plus functions.
ChrisA
No:
>>> def f():
... break
...
File "<stdin>", line 2
SyntaxError: 'break' outside loop
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Do not stand in a place of danger trusting in miracles.
-- (an Arab proverb)
No, "return" returns a value. Modules do not return values.
Therefore "return" would be inappropriate. If this feature were
deemed desirable, "break" would make more sense to me.
Yeah, I see what you mean. I wasn't talking about the actual break
keyword, but rather having a "break" in execution. Basically
execution of the current frame stops and returns; loop bodies aren't
handled in their own execution frames but effectively it's the same
idea.
So, a little namespace collision between us there on the words break
and return. Regardless, for the only real use case I had for module
breaking flow control, I have a better solution anyway. Thanks again
for your feedback.
-eric
> --
> Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
> San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
> Do not stand in a place of danger trusting in miracles.
> -- (an Arab proverb)
Yes:
def f():
return
print("Won't happen")
"break out of" doesn't necessarily require the break keyword per se.
You can abort a function part way, same as you can abort a loop part
way.
ChrisA
> Eric Snow wrote:
>>
>> The only ways that I know of to accomplish this currently is either by
>> putting everything inside if-else blocks, or raise some kind of
>> ImportBreak exception and catch it in an import hook.
>
> You're still not elucidating a very clear use case here. You want to do
> some tests and then break out of the top-level execution of the module
> if they happen. Just use `sys.exit`.
>
> It's still not clear _why_ this is useful. As I said, the typical
> behavior of a module is to define a lot of things, perhaps building up
> some needed data structures, and then do the `__name__ == "__main__"`
> test to see if it's being executed as a script, and then _do_ something.
I'm not entirely sure that this is a *good* use case, but I think the use
case that Eric Snow has in mind is something like this pseudo-code:
# === in module other.py which is not the main module ===
def spam(): pass
if some_condition: stop processing
def ham(): pass
def cheese(): pass
def salad(): pass
# === in the main module ===
import other
other.spam() # always defined
try:
other.ham
except AttributeError:
print "there is no ham"
sys.exit would be inappropriate, because the intention is not to exit the
entire application, but just to halt processing of the module. You could
wrap the def cheese inside an if block, but if there's a lot of
conditional code, then the majority of your module might be indented,
which seems silly.
If Python had GOTOs this would be a perfect use-case for jumping to a
label at the end of the file :)
Perhaps the most sensible alternative is conditional importing:
# === module extras.py ===
def ham(): pass
def cheese(): pass
def salad(): pass
# === module other.py ===
def spam(): pass
if not some_condition: from extras import *
--
Steven
This would, if I understand imports correctly, have ham() operate in
one namespace and spam() in another. Depending on what's being done,
that could be quite harmless, or it could be annoying (no sharing
module-level constants, etc).
As to which keyword is used, I would be inclined to go with 'return'
rather than 'break'. The module is thus a procedure in its own right.
Of course, that's assuming the feature's actually needed, which isn't
certain by any means.
ChrisA
Look back at the context. I was actually talking about the break keyword.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Human salvation lies in the hands of the creatively maladjusted.
-- Dr. Martin Luther King, Jr.
No, he's using `from ... import *`. It dumps it all in the same
namespace (which is usually why it's frowned upon, but in his example
it's kind of the point).
I don't see it as a very compelling solution beyond putting code using a
simple `if`. And it's still rather hard to imagine a serious use case.
> As to which keyword is used, I would be inclined to go with 'return'
> rather than 'break'. The module is thus a procedure in its own right.
> Of course, that's assuming the feature's actually needed, which isn't
> certain by any means.
Neither makes sense. `break` exits out of looping structures, which the
top-level code of a module most certainly is not. `return` returns out
of functions or methods and -- most importantly -- _returns something_.
(`return` without an argument returns None). Modules have no facility
to return anything, nor would it make much sense at all to do so.
This is an example of a problem that simply does not need solving with
additional language changes: There are already perfectly good (and,
perhaps more importantly, clear) facilities to do whatever it is you
want to do. If you want to exit, call `sys.exit`. If you want to
conditionally execute some code, use `if`. If you want to indicate an
exceptional condition, raise an exception.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Wrong, with a little bit right. The 'from ... *' functions are now
bound in the calling namespace, but they still execute in their original
namespace. Observe:
8<--these.py---------------------------------------------------------
import this
this.yummy()
8<--this.py----------------------------------------------------------
breakfast = 'ham and eggs'
def spam():
print(breakfast)
if 'spam' not in breakfast:
from that import *
8<--that.py----------------------------------------------------------
def yummy():
print(breakfast)
8<--results----------------------------------------------------------
--> import these
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "these.py", line 3, in <module>
this.yummy()
File "that.py", line 2, in yummy
print(breakfast)
NameError: global name 'breakfast' is not defined
8<-------------------------------------------------------------------
~Ethan~
The functions are defined in two separate global namespaces, though.
That means that the actual bindings visible to ham() are different
from the globals visible to spam(). Constants should be fine, but if
ham() modifies a global, then spam() won't see the change, and
vice-versa.
> Neither makes sense. `break` exits out of looping structures, which the
> top-level code of a module most certainly is not.
Why does that matter? It seems a bit like arguing that the `in`
keyword can't be used for membership testing, because it's already in
use in the for-loop syntax. It wouldn't be the first time Python has
reused a keyword.
The Context:
"It's quite consistent on which control structures you can break out of"
Hmmm.... Nope, nothing there to suggest you were talking about the
'break' keyword.
~Ethan~
That's what I wrote, all right, but not its context. I suspect you're
just being difficult.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Winners are men who have dedicated their whole lives to winning.
-- Woody Hayes
True. So let's use `in` to represent breaking out of the top-level code
of a module. Why not, it's not the first time a keyword has been
reused, right?
The point is, if it's not obvious already from that facetious proposal,
it's not a good idea to reuse keywords that really read very differently
than their original use. Reusing `break` (or `return`) this way would
be rather abusive.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Yes, using `in` to mean "break out of a block" would obviously be a
terrible choice, since the word "in" has nothing to do with breaking.
I really don't see why using `break` to mean "break out of a block" is
counter-intuitive, especially since as you point out it is already
used that way for two particular types of blocks. The proposed usage
merely adds a third type.
I think a stronger objection might be that it disrupts the homology of
`break` and `continue`, since continuing a module is meaningless.
The exact context was:
"""
Some of the complex statements have keywords that let you break out of
that execution, like break and continue in loops. Some do not.
"""
which is about the breaking keywords in general (break, continue,
return), not about break specifically.
Yes, which could be rephrased as the fact that `break` and `continue`
are restricted to looping control structures, so reusing `break` in this
context would be a bad idea. You know, kind of like the exact point I
made earlier which you're trying to nitpick in another reply.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Maybe I could see you / When this is over
-- Scritti Politti
Which is why I believe 'return' would be a better choice, even though
returning a value other than None would make no sense. It would simply
be a restriction, and one that almost nobody would notice - like this:
>>> def f():
yield 1
yield 2
yield 3
>>> a=f()
>>> a
<generator object f at 0x00FB4AA8>
>>> a.send(1)
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
a.send(1)
TypeError: can't send non-None value to a just-started generator
ChrisA
[...]
> Yes, which could be rephrased as the fact that `break` and `continue`
> are restricted to looping control structures, so reusing `break` in this
> context would be a bad idea. You know, kind of like the exact point I
> made earlier which you're trying to nitpick in another reply.
No offense is intended Erik, but in my experience, when people complain
about others nitpicking, they've usually said something which is *almost*
correct, i.e. wrong :)
Can we agree that the plain English verb "break", as in "to break out
of", can apply to any of:
* returning from a function
* yielding from an interator or generator
* raising an exception
* jumping via a GOTO (in languages that have GOTOs)
* exiting a loop via a break
* or any other way of exiting from a code block that I may have missed
and that only the fifth applies to the Python keyword "break"?
If we were to have a "exit this module early, but without exiting Python
altogether" statement, I'd consider "exit" to be the most descriptive
name, although it would clash with existing uses of the word, e.g.
sys.exit(). Overloading "break" strikes me as disagreeable, but not as
disagreeable as overloading "return" or "in" :)
--
Steven
I'd say let's not bikeshed on the name when the merits of "breaking"
out of a module's execution haven't been established, but what's the
point. <wink>
-eric
>>>> def f():
> yield 1
> yield 2
> yield 3
>
>
>>>> a=f()
>>>> a
> <generator object f at 0x00FB4AA8>
>>>> a.send(1)
> Traceback (most recent call last):
> File "<pyshell#7>", line 1, in <module>
> a.send(1)
> TypeError: can't send non-None value to a just-started generator
>
> ChrisA
This is all great and all, but specific references earlier in the thread
were made to not just the concept of "breaking out of things," but to
the `break`, `continue` (not relevant here), and `return` keywords. It
was these that I was discussing.
I simply pointed out why the first and last were not good ideas for
consistency reasons (the second was never proposed as a good idea).
And, most importantly, why the whole idea is not that useful to start
with; there already exist far better ways to achieve your goals that are
already supported in the language, clear, and self-documenting if used
properly.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
Do we really want to go to Mars / Do we really want to try
-- Cassandra Wilson
Just to throw another approach into the mix (because I was thinking
about the "finally" word), what about:
raise StopImport
along the lines of generators' "raise StopIteration".
Then the import machinery can catch it, no new keyword is needed and no
existing keyword needs feature creeping.
Cheers,
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
And it is not our part here to take thought only for a season, or for a few
lives of Men, or for a passing age of the world. - Gandalf the grey
> On 17Jun2011 06:00, Steven D'Aprano
> <steve+comp....@pearwood.info> wrote: | If we were to have a
> "exit this module early, but without exiting Python | altogether"
> statement, I'd consider "exit" to be the most descriptive | name,
> although it would clash with existing uses of the word, e.g. |
> sys.exit(). Overloading "break" strikes me as disagreeable, but not as |
> disagreeable as overloading "return" or "in" :)
>
> Just to throw another approach into the mix (because I was thinking
> about the "finally" word), what about:
>
> raise StopImport
>
> along the lines of generators' "raise StopIteration".
>
> Then the import machinery can catch it, no new keyword is needed and no
> existing keyword needs feature creeping.
The only problem is that the importing module needs to catch it, or else
you get a traceback. The importer shouldn't need to care what goes in
inside the module.
Something like this:
spam()
if condition:
exit # halt, stop, whatever
ham()
cheese()
should be the equivalent to:
spam()
if not condition:
ham()
cheese()
I don't think the use-case for this is convincing enough to need it, but
it's an interesting concept. I once played around with a mini-language
for config files that included a "STOP" command, so that:
key = value
STOP
everything under here is ignored
but I think it was a feature in search of a use.
--
Steven
Isn't that how Perl's __data__ keyword works? (Long time since I've
used it, it mightn't be quite __data__.)
ChrisA
Not quite. In my config language, "ignored" means ignored. There was no
way of accessing the rest of the file, short of guessing the file name,
opening it and reading it as text.
In Perl, the __END__ and __DATA__ keywords mark the end of the Perl
program, and leave the rest of the document visible to the caller via a
special file handle:
http://www.perl-programming.info/difference-btw-__end__-and-__data__
You know, I actually kinda like that...
--
Steven
Sure, but if you don't use that handle, it comes to the same thing.
It's like a function's return value when you just want its side
effects, or using re.match and ignoring all but whether it evaluates
as True or False. In REXX, you can access any part of the source file
using the sourceline() function - sometimes I've done things like
this:
/*
Usage: scriptname [arg] [arg] [arg]
arg: specifies the number of times to yell Argh
arg: specifies the type of black beast to kill you
arg: chooses an Abstract Resource Group
Use this only in cases of blargh.
*/
.
.
.
.
usage:
do i=2 to sourceline() until sourceline(i)="*/"; say sourceline(i); end
Does this mean that the comment isn't ignored? Nope. It's ignored, but
it can be retrieved through in-language means.
Anyhow, it's not uncommon to abuse language features to do different
things. I've heard that it's faster in MS-DOS Batch to put comments
with a leading colon (making them labels for goto) than to use the REM
(remark) command...
ChrisA
I was thinking the import mechanism itself would catch it, not the user
of the "import" statement. Just as this:
for i in iterator:
...
quietly ceases the loop when the iterator raises StopIteration, the
importer would consider a module that raised StopImport during the import
to have finished its import successfully.
So the caller does an:
import foo
as normal, with no special wrapping. And the module goes:
spam()
if condition:
raise StopIteration
ham()
cheese()
Cheers,
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
In article <323C4D...@ss1.csd.sc.edu>, lhar...@ss1.csd.sc.edu wrote:
| It still is true that the best touring bike is the one that you are
| riding right now. Anything can be used for touring. As long as you
| can travel, you are touring.
I beleive such true and profound statements are NOT allowed to be posted
in this newsgroup, and are also against the charter. You've been warned.
- Randy Davis DoD #0013 <ra...@agames.com> in rec.moto
Of course, that should be StopImport, not StopIteration.
Cheers,
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
Agree, for Law is costly. -- Very good advice to litigious Persons, founded
upon Reason and Experience; for many Times the Charges of a Suit exceed the
Value of the Thing in Dispute. - Bailey's dictionary, 1736