Hi, Folks-
I have a question regarding the "proper" use of try: finally:... Consider
some code like this:
d = Device.open()
try:
d.someMethodThatCanRaiseError(...)
if SomeCondition:
raise Error # Error is subclass of Exception
d.someMethodThatCanRaiseError(...)
... lots of other methods on d that can raise Error
finally:
d.close()
When I run this code, and an Error is raised, I get traceback (which I don't
want) and the program terminates (which I don't want). However, putting in
each method that can raise Error into a try: except: block doesn't help,
because I need to re-raise Error to break out of the block and get the
finally: to be triggered:
d = Device.open()
try:
try:
d.someMethodThatCanRaiseError(...)
except Error:
# Do something here
raise Error
if SomeCondition:
raise Error # Error is subclass of Exception
try:
d.someMethodThatCanRaiseError(...)
except Error:
# Do something here
raise Error
... lots of other methods on d that can raise Error
finally:
d.close()
I almost feel like I need a goto statement! Am I missing something about
finally:, or is it really not altogther very useful in practice?
Thanks,
-Don 26 2407
djw wrote: I have a question regarding the "proper" use of try: finally:... Consider some code like this: [...] When I run this code, and an Error is raised, I get traceback (which I don't want) and the program terminates (which I don't want).
I'm sorry if I misinterpret what you want, but it sounds like you
need nothing more than an enclosing try/except.
d = Device.open()
try:
try:
d.someMethodThatCanRaiseError(...)
if SomeCondition:
raise Error # Error is subclass of Exception
d.someMethodThatCanRaiseError(...)
... lots of other methods on d that can raise Error
finally:
d.close()
except:
# whatever you want here
Is anything wrong with that?
In article <O6********************@powergate.ca>,
Peter Hansen <pe***@engcorp.com> wrote: djw wrote:
I have a question regarding the "proper" use of try: finally:... Consider some code like this: [...] When I run this code, and an Error is raised, I get traceback (which I don't want) and the program terminates (which I don't want).
I'm sorry if I misinterpret what you want, but it sounds like you need nothing more than an enclosing try/except.
d = Device.open() try: try: d.someMethodThatCanRaiseError(...) if SomeCondition: raise Error # Error is subclass of Exception d.someMethodThatCanRaiseError(...) ... lots of other methods on d that can raise Error finally: d.close() except: # whatever you want here
Is anything wrong with that?
Didn't seem to be what he wanted, though. The best I could
make out was that he wanted a handler that receives control
on the exception, but leaves the exception in force enough
to cause an unwind to the next handler. He has a specific
exception handler for each step in a procedure, but doesn't
want to explicitly decide, in the handler, where to go next.
Didn't really see what it had to do with "finally", except
that in his example it was the next handler.
Donn Cave, do**@u.washington.edu
Peter Hansen wrote: djw wrote:
I have a question regarding the "proper" use of try: finally:... Consider some code like this: [...] When I run this code, and an Error is raised, I get traceback (which I don't want) and the program terminates (which I don't want).
I'm sorry if I misinterpret what you want, but it sounds like you need nothing more than an enclosing try/except.
d = Device.open() try: try: d.someMethodThatCanRaiseError(...) if SomeCondition: raise Error # Error is subclass of Exception d.someMethodThatCanRaiseError(...) ... lots of other methods on d that can raise Error finally: d.close() except: # whatever you want here
Is anything wrong with that?
OK, yeah, I think you are correct. What wasn't apparent to me is that a
finally: doesn't stop the exception from continuing to propagate. I just
wish you could intermix except: and finally: within the same try: block.
Thanks,
Don
djw wrote: OK, yeah, I think you are correct. What wasn't apparent to me is that a finally: doesn't stop the exception from continuing to propagate. I just wish you could intermix except: and finally: within the same try: block.
You used to be able to do that, according to a recent thread on the
subject. It was removed because it was ambiguous what would happen.
For example, if an exception were raised in a finally clause which
came just before the except clause, would the except clause catch it?
Since the finally is technically outside of the try block, some
people thought it shouldn't be caught by the following except.
Others did. Guido nuked it.
Anyway, it would be purely syntactic sugar for what we have now,
saving you a few keystrokes and one extra level of indentation.
No big deal.
-Peter
Op 2004-07-06, Peter Hansen schreef <pe***@engcorp.com>: djw wrote:
OK, yeah, I think you are correct. What wasn't apparent to me is that a finally: doesn't stop the exception from continuing to propagate. I just wish you could intermix except: and finally: within the same try: block.
You used to be able to do that, according to a recent thread on the subject. It was removed because it was ambiguous what would happen. For example, if an exception were raised in a finally clause which came just before the except clause, would the except clause catch it? Since the finally is technically outside of the try block, some people thought it shouldn't be caught by the following except. Others did. Guido nuked it.
Anyway, it would be purely syntactic sugar for what we have now, saving you a few keystrokes and one extra level of indentation. No big deal.
I don't agree. It is not unusual to nest try blocks. If you then
need to two instead of one because you can't combine a finally
with an except clause, you almost double the level of indentations.
IMO it is almost as bad as would not having an elif and needing
an extra indentation level for each else .. if
--
Antoon Pardon
Antoon Pardon wrote: Op 2004-07-06, Peter Hansen schreef <pe***@engcorp.com>:
[about using finally and except on the same try block]You used to be able to do that, according to a recent thread on the subject. It was removed because it was ambiguous what would happen. For example, if an exception were raised in a finally clause which came just before the except clause, would the except clause catch it? Since the finally is technically outside of the try block, some people thought it shouldn't be caught by the following except. Others did. Guido nuked it.
Anyway, it would be purely syntactic sugar for what we have now, saving you a few keystrokes and one extra level of indentation. No big deal.
I don't agree.
With what statement don't you agree? The part about "you used to
be able to do that... [but] it was ambiguous ... Guido nuked it."?
Because that's a fact. It's hard not to agree with it...
And if it's the part about "syntactic sugar", then you should
understand that the term refers to alternate syntax which is
seen as "cleaner" or "simpler" in some way, but which is not
otherwise different in any way that affects the parse tree or
resulting code. And unless you think combined finally/except
clauses should be treated differently in the generated bytecode
than nested try/finally/except, it's *still* a fact that it
would just be "syntactic sugar", and arguing against facts is
pretty hard to do...
It is not unusual to nest try blocks. If you then need to two instead of one because you can't combine a finally with an except clause, you almost double the level of indentations.
In fact, you would precisely double the level of indentations.
It seems that's the price we have to pay for being human, since
apparently our brains aren't all wired the same way and allowing
finally/except to be combined was likely to lead to subtle bugs.
IMO it is almost as bad as would not having an elif and needing an extra indentation level for each else .. if
Almost, perhaps. But can you see any way for similar ambiguity
to arise in the case of if/elif/else blocks? I think everybody
understands how they work just fine. The whole point is that
not everybody understood how the try/finally/except thing worked
(or they didn't agree with how it _should_ work).
I understand that you are arguing that it would be nicer to
allow try/finally/except. I agree! Unfortunately, (a) it was
removed and is probably unlikely to be added back in, (b) it
was ambiguous, and the ambiguity has not been resolved, so
until you or someone else can come up with a better approach
(and write a PEP) it will stay the way it is. And that's just
another fact, so it's pointless to try to argue against it.
Hmm... Also, I think it really *is* unusual (as in, "not usual"
meaning not really common) to nest try blocks. At least, I
recall lone try/finally or try/except blocks being much much
more common in most code than a mix. Perhaps my memory is
poor on this. Perhaps someone will actually go and research
it and prove it one way or the other. If it really is
very common, it might be worth revisiting the subject...
If it's not very common, then this is once again just another
discussion about syntactic sugar for an uncommon use case,
and that kind of thing is so last year. And the year before.
And....
-Peter
Peter Hansen wrote:
[snip] Hmm... Also, I think it really *is* unusual (as in, "not usual" meaning not really common) to nest try blocks. At least, I recall lone try/finally or try/except blocks being much much more common in most code than a mix. Perhaps my memory is poor on this. Perhaps someone will actually go and research it and prove it one way or the other. If it really is very common, it might be worth revisiting the subject... If it's not very common, then this is once again just another discussion about syntactic sugar for an uncommon use case, and that kind of thing is so last year. And the year before. And....
-Peter
I am suprised that what I am trying to accomplish is unusual. Basically, I
want to acquire some resource/object (that requires cleanup). Then make
some calls against that object/resource, catching any excpetions along the
way (assuming that try/except is the right way to do this). If anything bad
happens, I want stop opererating on the object and insure that the object
is cleaned up (presumably a finally is the best way to do this).
This seems like a really normal bit of code to me. I am suprised there isn't
a more elegant way to handle this (I thought that try/except/finally would
come to the rescue, but...) Is there a better way to handle this situation?
-Don
djw wrote: Peter Hansen wrote:Hmm... Also, I think it really *is* unusual (as in, "not usual" meaning not really common) to nest try blocks. I am suprised that what I am trying to accomplish is unusual. Basically, I want to acquire some resource/object (that requires cleanup).
It *is* unusual, in the way I mean, because relatively little code
is involved with resource cleanup when it's required (in Python,
anyway), and relatively little resource cleanup is required when
programming, in general.
This seems like a really normal bit of code to me.
Maybe I'm drawing too fine a line here. I'm using "usual" and
"unusual" in the sense of "frequently occurring or not", rather than
in the sense of "normal or really weird".
It's very normal. It's just not so frequently occurring that
the nested finally/except should be seen as a major roadblock.
Not that one example tells much about the general case, but: I
just wrote a little inventory-tracking application, very small.
It has one finally (for a database commit), and two excepts
(basically around things that could have been if/thens but
are slightly cleaner as exception handling code). None of
these cases required bringing in a nested try. I think that's
the "usual" pattern.
If you find yourself needing to write such things very often,
I think you're probably not writing your code in a very modular
way, as it would then be more reusable and therefore require
being written much less often...
-Peter
In article <40******@usenet01.boi.hp.com>, djw <do**********@hp.com>
wrote: Peter Hansen wrote:
[snip] Hmm... Also, I think it really *is* unusual (as in, "not usual" meaning not really common) to nest try blocks. At least, I recall lone try/finally or try/except blocks being much much more common in most code than a mix. Perhaps my memory is poor on this. Perhaps someone will actually go and research it and prove it one way or the other. If it really is very common, it might be worth revisiting the subject... If it's not very common, then this is once again just another discussion about syntactic sugar for an uncommon use case, and that kind of thing is so last year. And the year before. And....
-Peter
I am suprised that what I am trying to accomplish is unusual. Basically, I want to acquire some resource/object (that requires cleanup). Then make some calls against that object/resource, catching any excpetions along the way (assuming that try/except is the right way to do this). If anything bad happens, I want stop opererating on the object and insure that the object is cleaned up (presumably a finally is the best way to do this).
This seems like a really normal bit of code to me. I am suprised there isn't a more elegant way to handle this (I thought that try/except/finally would come to the rescue, but...) Is there a better way to handle this situation?
Not per se. My reflex would be to suggest more functions,
like
def f(p0, p1):
t = acquire_resource(p0)
try:
v = ft(p1)
finally:
release_resource(t)
return v
def ft(p1):
try:
x = g(p1)
except Eg, ev:
print >> sys.stderr, ev
return None
try:
return fx(x)
except:
gu(x)
raise
def fx(x):
try:
return fy(h(x))
except Eh, ev:
print >> sys.stderr, ev
raise
etc. Note that the exception handling will be more or
less elaborate depending on how much you can take for
granted about what exceptions may be raised, what state
you need to recover from them, etc.'
Conceptually, what you're after is a nested try: block,
like
try:
x = g(p1)
try:
y = h(x)
try:
...
except:
...
except:
handle h error
except:
handle g error
That's how you handle an exception from g without
proceeding to h, with try/except alone. I don't find
that grossly wrong, it's just more palatable with a
few functions when it gets very deep.
Donn Cave, do**@u.washington.edu
Peter Hansen wrote: djw wrote:
Peter Hansen wrote:Hmm... Also, I think it really *is* unusual (as in, "not usual" meaning not really common) to nest try blocks. I am suprised that what I am trying to accomplish is unusual. Basically, I want to acquire some resource/object (that requires cleanup).
It *is* unusual, in the way I mean, because relatively little code is involved with resource cleanup when it's required (in Python, anyway), and relatively little resource cleanup is required when programming, in general.
I would agree (with regards to straight Python), but I disagree when you
include I/O. The I/O I am interacting with requires cleanup. Simply
allowing the device object I created to go out of scope and be
automatically cleaned up does not cause the I/O to be cleaned up properly. This seems like a really normal bit of code to me. Maybe I'm drawing too fine a line here. I'm using "usual" and "unusual" in the sense of "frequently occurring or not", rather than in the sense of "normal or really weird".
It's very normal. It's just not so frequently occurring that the nested finally/except should be seen as a major roadblock. Not that one example tells much about the general case, but: I just wrote a little inventory-tracking application, very small. It has one finally (for a database commit), and two excepts (basically around things that could have been if/thens but are slightly cleaner as exception handling code). None of these cases required bringing in a nested try. I think that's the "usual" pattern.
If you find yourself needing to write such things very often, I think you're probably not writing your code in a very modular way, as it would then be more reusable and therefore require being written much less often...
Point taken. Its not that I'm doing this that often, its just when I do it
seems awkward. Since I find most Python code to be rather elegant and
concise, awkward situations like this tend to stick out glaringly to me.
-Don -Peter
Op 2004-07-07, Peter Hansen schreef <pe***@engcorp.com>: Antoon Pardon wrote:
Op 2004-07-06, Peter Hansen schreef <pe***@engcorp.com>: [about using finally and except on the same try block]You used to be able to do that, according to a recent thread on the subject. It was removed because it was ambiguous what would happen. For example, if an exception were raised in a finally clause which came just before the except clause, would the except clause catch it? Since the finally is technically outside of the try block, some people thought it shouldn't be caught by the following except. Others did. Guido nuked it.
Anyway, it would be purely syntactic sugar for what we have now, saving you a few keystrokes and one extra level of indentation. No big deal.
I don't agree.
With what statement don't you agree? The part about "you used to be able to do that... [but] it was ambiguous ... Guido nuked it."?
That it is no big deal.
Because that's a fact. It's hard not to agree with it...
And if it's the part about "syntactic sugar", then you should understand that the term refers to alternate syntax which is seen as "cleaner" or "simpler" in some way, but which is not otherwise different in any way that affects the parse tree or resulting code. And unless you think combined finally/except clauses should be treated differently in the generated bytecode than nested try/finally/except, it's *still* a fact that it would just be "syntactic sugar", and arguing against facts is pretty hard to do...
It is not unusual to nest try blocks. If you then need to two instead of one because you can't combine a finally with an except clause, you almost double the level of indentations. In fact, you would precisely double the level of indentations. It seems that's the price we have to pay for being human, since apparently our brains aren't all wired the same way and allowing finally/except to be combined was likely to lead to subtle bugs.
Oh come on, I though python was for consenting adults?
Personnaly I think that allowing += operators for unmutable
object will lead to subtle bugs too, because if you see
code like
b = a
a += c
You don't know whether a and b are still the same object or not.
This will IMO be more confusing then a combined finally, except
clause, because the latter can be clearly documented in how
it behaves, while the above depends on the type of the variables. IMO it is almost as bad as would not having an elif and needing an extra indentation level for each else .. if
Almost, perhaps. But can you see any way for similar ambiguity to arise in the case of if/elif/else blocks? I think everybody understands how they work just fine. The whole point is that not everybody understood how the try/finally/except thing worked (or they didn't agree with how it _should_ work).
So what? When I complained about the ambiguity that was introduced
by the introduction of the += and like operators, people told me
that:
1) Error caused by not reading the docs carefull enough were
my own fault
2) That I could always write things in such a way that there
would be no ambiguity.
So these arguments seem to be just as valid with a combined
except: finaly: clause.
I understand that you are arguing that it would be nicer to allow try/finally/except. I agree! Unfortunately, (a) it was removed and is probably unlikely to be added back in, (b) it was ambiguous, and the ambiguity has not been resolved, so until you or someone else can come up with a better approach (and write a PEP) it will stay the way it is. And that's just another fact, so it's pointless to try to argue against it.
Well I think it really isn't that hard to define the behaviour
of
try:
except expr1:
finaly:
except expr2:
to be the same as
try:
try:
try:
except expr1:
finaly:
except expr2:
In fact if it wasn't for the indentations rules in python
I wouldn't care because without them I could simply write
something like
try: try: try:
except expr1:
finaly:
except expr2:
which is how I write my if ... else blocks in C.
However I'm not going to write a PEP. The impression that there
is some double standard going on is just too strong, where powerfull,
flexible and/or ambiguous concepts that are in the language are defended
with the argument that python is for consenting adults and
powerfull, flexible and/or ambiguous concepts that are not
in the language are opposed because they can lead to subtle
bugs.
Maybe the python community should make up its mind and decide
what it wants. A language for consenting adults or protection
against subtle bugs.
Hmm... Also, I think it really *is* unusual (as in, "not usual" meaning not really common) to nest try blocks. At least, I recall lone try/finally or try/except blocks being much much more common in most code than a mix. Perhaps my memory is poor on this. Perhaps someone will actually go and research it and prove it one way or the other. If it really is very common, it might be worth revisiting the subject... If it's not very common, then this is once again just another discussion about syntactic sugar for an uncommon use case, and that kind of thing is so last year. And the year before. And....
One can argue the opposite too. Why remove it, if the subtle
bugs can occur only in unusual cases. Let those who need it
and know what they are doing use it. That is what I understand
about a language for consenting adults.
--
Antoon Pardon
Antoon Pardon wrote: Op 2004-07-07, Peter Hansen schreef <pe***@engcorp.com>: Personnaly I think that allowing += operators for unmutable object will lead to subtle bugs too, because if you see code like
b = a a += c
You don't know whether a and b are still the same object or not.
I agree with you on this one. I don't like the way += etc
works. Also don't use it except for integers...
Well I think it really isn't that hard to define the behaviour of
try: except expr1: finaly: except expr2:
to be the same as
try: try: try: except expr1: finaly: except expr2:
Interesting, except that this is *not* how it was implemented
before. Why don't you write a PEP and see if you can get your
solution to the problem implemented? Presenting it as a reason
why the previous, *different* solution should have been kept
doesn't make sense.
However I'm not going to write a PEP.
Dang.
Maybe the python community should make up its mind and decide what it wants. A language for consenting adults or protection against subtle bugs.
It wants to avoid subtle bugs, but unfortunately it sometimes
makes mistakes in how it does that.
One can argue the opposite too. Why remove it, if the subtle bugs can occur only in unusual cases. Let those who need it and know what they are doing use it. That is what I understand about a language for consenting adults.
You misunderstand (IMHO) what "consenting adults" is about.
I tried to make the point in a previous thread about subtle
problems with threads... some types of bugs are too subtle
to allow the consenting adults thing to hold sway. That's
just my opinion, though. I'm not sure it's really shared by
anyone else in the community.
Threads I happen to know very well, and know many (but perhaps
not all) of the risks involved. I also know very many good
programmers who don't really understand threading issues
fully, yet. Nobody knows how to test well for threading
problems, so advice like "always use a Queue" is best.
Exceptions are not generally things that are exercised by
normal application runs, or even by most unit tests (unless
you are doing test-driven development). Therefore subtle
problems with exceptions should be "disallowed" by appropriate
language changes.
Something like += should work exactly like people expect
it to. The fact that it sometimes doesn't means it is a
wart and we should reconsider it. That probably won't happen,
so we're stuck with it. (?)
The thing that "consenting adults" usually applies to is
either access control (private, public, etc), or types.
Improvements in the area of types are expected in the future,
so let's ignore that one. Access control: this is now
pretty well understood to be a "problem" that is more in
the programmer's brain than in reality. Not having it in
the BSDM (BDSM?) style of C++ or Java doesn't lead to
subtle bugs, and the huge number of working Python programs
which have *no* access specifiers (or whatever they're called)
proves the point.
I'd go on, but thankfully for those of you reading I've got
a meeting I can just barely make it to so I'll stop here. :-)
-Peter
Op 2004-07-08, Peter Hansen schreef <pe***@engcorp.com>: Antoon Pardon wrote:
Op 2004-07-07, Peter Hansen schreef <pe***@engcorp.com>: Personnaly I think that allowing += operators for unmutable object will lead to subtle bugs too, because if you see code like
b = a a += c
You don't know whether a and b are still the same object or not. I agree with you on this one. I don't like the way += etc works. Also don't use it except for integers...
Well I think it really isn't that hard to define the behaviour of
try: except expr1: finaly: except expr2:
to be the same as
try: try: try: except expr1: finaly: except expr2:
Interesting, except that this is *not* how it was implemented before. Why don't you write a PEP and see if you can get your solution to the problem implemented? Presenting it as a reason why the previous, *different* solution should have been kept doesn't make sense.
However I'm not going to write a PEP.
Dang.
Well I might reconsider. But I have no experience with this
whatsoever and my impression is that it is a rather involved
undertaking. In any case I doubt that it will be accepted
for the following reason: The proposal suggest that
try:
except expr1:
except expr2:
would be the same as
try:
try:
except expr1:
except expr2
which isn't the case
So maybe defining behaviour that is consistent with current
behaviour wouldn't be so simple after all. Maybe the python community should make up its mind and decide what it wants. A language for consenting adults or protection against subtle bugs.
It wants to avoid subtle bugs, but unfortunately it sometimes makes mistakes in how it does that.
One can argue the opposite too. Why remove it, if the subtle bugs can occur only in unusual cases. Let those who need it and know what they are doing use it. That is what I understand about a language for consenting adults.
You misunderstand (IMHO) what "consenting adults" is about. I tried to make the point in a previous thread about subtle problems with threads... some types of bugs are too subtle to allow the consenting adults thing to hold sway. That's just my opinion, though. I'm not sure it's really shared by anyone else in the community.
The problem is, everybody has an other opinion about which
types of bugs are too subtle. People who want to put some
feature in the language that can limit the programmer
mostly do because they want to avoid bugs which they consider
too subtle, so how do we determine which bugs are realy
too subtle and which are not? My impresion here is that
most people just use themselves as yardstick here and
declares those bugs that are too subtle for them as
being too subtle in general. IMO if you don't like it
when others say a feature will introduce too subtle
bugs too allow, when you feel you will be able to
cope, you shouldn't use the same argument. If you are
not comfortable with something, just avoid it and
code in a different way instead of making it impossible
for others to use.
Threads I happen to know very well, and know many (but perhaps not all) of the risks involved. I also know very many good programmers who don't really understand threading issues fully, yet. Nobody knows how to test well for threading problems, so advice like "always use a Queue" is best.
Sure, but lets look at the problem of not allowing one
thread to pause, interrupt or raise an exception in
an other thread. The defense for not allowing these
things has been that they would introduce suble bugs.
However it is my feeling that not allowing them will
sometimes complicate the code unnecessary. Suppose
you have a very complicated algorithm that you want
to start in a seperate thread. Suppose that this is
in a gui program and you want to allow the user
to interrupt the process if he finds it is taking too
long. Since this is not just a while loop, you are
now obligated to springle the code with test that
check whether or not the user wants to interrupt.
If one thread could raise an exception in an other
one, this could be far easier.
I agree Queues are in general a good solution, but
sometimes they are not and cramming a situation
that doesn't fit a Queue in one anyway just increases
the mess.
Exceptions are not generally things that are exercised by normal application runs, or even by most unit tests (unless you are doing test-driven development). Therefore subtle problems with exceptions should be "disallowed" by appropriate language changes.
I don't agree with that logic.
Something like += should work exactly like people expect it to. The fact that it sometimes doesn't means it is a wart and we should reconsider it. That probably won't happen, so we're stuck with it. (?)
Well I wouldn't mind if it wouldn't work exactly as I expected.
What I expect is not always correct. However I do think that
it is important that behaviour in a language is consistent.
If += would always have yielded a new object, that is something
I could have more easily lived with because after maybe a first
surprise the behaviour would be consistent and thus predictable.
The thing that "consenting adults" usually applies to is either access control (private, public, etc), or types. Improvements in the area of types are expected in the future, so let's ignore that one. Access control: this is now pretty well understood to be a "problem" that is more in the programmer's brain than in reality. Not having it in the BSDM (BDSM?) style of C++ or Java doesn't lead to subtle bugs, and the huge number of working Python programs which have *no* access specifiers (or whatever they're called) proves the point.
But IMO it could go further. One program can signal an other.
That is an old practice that still is around. So why not
allow one thread to "signal" an other.
--
Antoon Pardon
Antoon Pardon wrote: Sure, but lets look at the problem of not allowing one thread to pause, interrupt or raise an exception in an other thread. The defense for not allowing these things has been that they would introduce suble bugs.
Actually, I think it's only interrupting that's been
discussed, and the main issues are (a) what to do if
the thread is blocked in an external (extension) call,
and (b) if the answer to (a) is "nuke the thread anyway!"
then what to do about cleanup.
Pausing shouldn't be an issue, though I'm not sure I
know any decent usecase for it. Raising an exception
should be pretty straightforward, and I have sneaking
suspicion (actually, it's a memory, and probably a wrong
one!) that that's how it's done in the addition that was
made to the core recently via a call in an extension
(Google Groups would bring up a message from Alex Martelli
describing it, I believe, or was it Aahz?).
If one thread could raise an exception in an other one, this could be far easier.
Anyone interested should try to dig up that past reference
to an addition that was made to allow killing threads.
I ought to remember whether it raised an exception, but
I don't. I agree that would probably be the best way
to handle it, but a lot of people who insist they need
thread killing will probably be disappointed if it can't
kill a thread that is caught in an external routine, or
if it can kill such threads, they will end up writing
code that is buggy because it doesn't clean things up
properly... oh well.
But IMO it could go further. One program can signal an other. That is an old practice that still is around. So why not allow one thread to "signal" an other.
Sounds easy to say, but what does it mean? What actually
happens in the thread that is signalled? How does it process
the signal if it's blocked, say in a socket.accept() call,
for two minutes?
Op 2004-07-08, Peter Hansen schreef <pe***@engcorp.com>: Antoon Pardon wrote:
Sure, but lets look at the problem of not allowing one thread to pause, interrupt or raise an exception in an other thread. The defense for not allowing these things has been that they would introduce suble bugs. Actually, I think it's only interrupting that's been discussed,
Well the few times I saw the discussion coming up I
tried to expand it, but with little succes.
and the main issues are (a) what to do if the thread is blocked in an external (extension) call, and (b) if the answer to (a) is "nuke the thread anyway!" then what to do about cleanup.
Well my first thought would be to send the thread a
signal. This way an extension call could install
a signal handler if it needed to cleanup things.
Pausing shouldn't be an issue, though I'm not sure I know any decent usecase for it. Raising an exception should be pretty straightforward, and I have sneaking suspicion (actually, it's a memory, and probably a wrong one!) that that's how it's done in the addition that was made to the core recently via a call in an extension (Google Groups would bring up a message from Alex Martelli describing it, I believe, or was it Aahz?).
Yes I found something but it seems only available in
extension code. If one thread could raise an exception in an other one, this could be far easier.
Anyone interested should try to dig up that past reference to an addition that was made to allow killing threads. I ought to remember whether it raised an exception, but I don't. I agree that would probably be the best way to handle it, but a lot of people who insist they need thread killing will probably be disappointed if it can't kill a thread that is caught in an external routine, or if it can kill such threads, they will end up writing code that is buggy because it doesn't clean things up properly... oh well.
People write buggy code all the time. Even in none threaded
code it might be necessary to cleanup things, and it isn't
done properly because people didn't anticipate a particular
exception being raised. But IMO it could go further. One program can signal an other. That is an old practice that still is around. So why not allow one thread to "signal" an other.
Sounds easy to say, but what does it mean? What actually happens in the thread that is signalled?
The same that happens in a program that is signaled.
The signalhanler is called.
How does it process the signal if it's blocked, say in a socket.accept() call, for two minutes?
Well what happens in a program that gets signalled and
is blocked in a socket.accept() call for two minutes?
Well I went to look at the signal documentation and I must
say I'm a bit annoyed by how signals are handled in python.
As I understand it is impossible to interrupt a python
program by typing ^C, while it is running extension code.
The interruption will occur when the extension code is
done. I think this is a bad idea.
--
Antoon Pardon
"djw" <do**********@hp.com> wrote in message
news:40******@usenet01.boi.hp.com... Peter Hansen wrote:
djw wrote:
Peter Hansen wrote: Hmm... Also, I think it really *is* unusual (as in, "not usual" meaning not really common) to nest try blocks.
I am suprised that what I am trying to accomplish is unusual.
Basically, I want to acquire some resource/object (that requires cleanup).
It *is* unusual, in the way I mean, because relatively little code is involved with resource cleanup when it's required (in Python, anyway), and relatively little resource cleanup is required when programming, in general.
I would agree (with regards to straight Python), but I disagree when you include I/O. The I/O I am interacting with requires cleanup. Simply allowing the device object I created to go out of scope and be automatically cleaned up does not cause the I/O to be cleaned up properly.
Why don't you define __del__() in the object so it can do its own cleanup?
Apologies if I've missed something important.
Nick
Nick Smallbone wrote: "djw" <do**********@hp.com> wrote:I would agree (with regards to straight Python), but I disagree when you include I/O. The I/O I am interacting with requires cleanup. Simply allowing the device object I created to go out of scope and be automatically cleaned up does not cause the I/O to be cleaned up properly. Why don't you define __del__() in the object so it can do its own cleanup?
Apologies if I've missed something important.
Yeah, all the past and recent threads talking about how you can't
really rely on __del__(). ;-)
-Peter
Peter Hansen <pe***@engcorp.com>
wrote on Wed, 07 Jul 2004 12:11:22 -0400: I understand that you are arguing that it would be nicer to allow try/finally/except. I agree! Unfortunately, (a) it was removed and is probably unlikely to be added back in, (b) it was ambiguous, and the ambiguity has not been resolved, so until you or someone else can come up with a better approach (and write a PEP) it will stay the way it is. And that's just another fact, so it's pointless to try to argue against it.
In Java, try...catch...finally has a very clearly defined order: the
try block is performed, if there's an exception it goes to the first
matching catch, and then whether or not there was an exception, the
finally block is performed. Sometimes this leads to flags that have to
be tested in the finally block to decide what to do, but at least it's
consistent and avoids repeated cleanup code.
But Python is not Java, nor should it be, and there's no particular
problem with one additional nesting layer to indicate exactly what
sequence things are done in.
--
<a href="http://kuoi.asui.uidaho.edu/~kamikaze/"> Mark Hughes </a>
"The void breathed hard on my heart, turning its illusions to ice, shattering
them. Was reborn, then, free to scrawl own design on this morally blank
world. Was Rorschach." --Alan Moore, _Watchmen #6_, "The Abyss Gazes Also"
[Peter Hansen] I understand that you are arguing that it would be nicer to allow try/finally/except. I agree! Unfortunately, (a) it was removed and is probably unlikely to be added back in, (b) it was ambiguous, and the ambiguity has not been resolved, so until you or someone else can come up with a better approach (and write a PEP) it will stay the way it is. And that's just another fact, so it's pointless to try to argue against it.
[Mark 'Kamikaze' Hughes] In Java, try...catch...finally has a very clearly defined order: the try block is performed, if there's an exception it goes to the first matching catch, and then whether or not there was an exception, the finally block is performed.
Ancient Python also had a clearly defined order, but that doesn't
matter: the point was that, in practice, people couldn't remember the
details, and routinely wrote broken code as a result. There's nothing
especially compelling about either way of resolving the question (note
that an enthusiastic "but it's obvious that an exception raised during
an 'except' clause should not enter the 'finally' block!" was one old
response in this thread), and Python doesn't allow int+string for
exactly the same reason. Not because it can't be defined clearly, but
because any way of defining it is so arbitrary it leaves half of
programmers believing that the other way of defining it was "the only
obvious" way. Don't allow mixing except with finally, and the
programmer has to be explicit about their intent. That was (and
remains) a Pythonic solution.
Tim Peters wrote: Not because it can't be defined clearly, but because any way of defining it is so arbitrary it leaves half of programmers believing that the other way of defining it was "the only obvious" way. Don't allow mixing except with finally, and the programmer has to be explicit about their intent. That was (and remains) a Pythonic solution.
Out of curiosity, what would be wrong with allowing both, but
insisting that the finally block (if it exists ) must come last? The
code layout would then clearly suggest the semantics: the finally comes
last. This is the thing I most often want to write anyway.
--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
[Tim] Not because it can't be defined clearly, but because any way of defining it is so arbitrary it leaves half of programmers believing that the other way of defining it was "the only obvious" way. Don't allow mixing except with finally, and the programmer has to be explicit about their intent. That was (and remains) a Pythonic solution.
[OKB (not okblacke)] Out of curiosity, what would be wrong with allowing both, but insisting that the finally block (if it exists ) must come last?
Please read the thread from its start. That *is* what Python used to do.
...
Tim Peters wrote: [OKB (not okblacke)] Out of curiosity, what would be wrong with allowing both, but insisting that the finally block (if it exists ) must come last? Please read the thread from its start. That *is* what Python used to do.
Oh, ok. The only message I've seen in this thread describing the
behavior was:
[Peter Hansen]For example, if an exception were raised in a finally clause which came just before the except clause, would the except clause catch it?
Which seems to be saying that finally clauses could come before
except clauses.
--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
OKB (not okblacke) wrote: Oh, ok. The only message I've seen in this thread describing the behavior was:
[Peter Hansen]
For example, if an exception were raised in a finally clause which came just before the except clause, would the except clause catch it?
Which seems to be saying that finally clauses could come before except clauses.
No, it seems to be a question, clearly (now that Tim has spoken)
showing my ignorance on the subject. I never saw Python before this
feature was removed, so you can't take a question from me as being
in any way authoritative about the features it asks about...
-Peter
Tim Peters <ti********@gmail.com> wrote:
.... Ancient Python also had a clearly defined order, but that doesn't matter: the point was that, in practice, people couldn't remember the details, and routinely wrote broken code as a result. There's nothing especially compelling about either way of resolving the question (note that an enthusiastic "but it's obvious that an exception raised during an 'except' clause should not enter the 'finally' block!" was one old response in this thread), and Python doesn't allow int+string for exactly the same reason. Not because it can't be defined clearly, but because any way of defining it is so arbitrary it leaves half of programmers believing that the other way of defining it was "the only obvious" way. Don't allow mixing except with finally, and the programmer has to be explicit about their intent. That was (and remains) a Pythonic solution.
Why is this not an argument for disallowing multiple except blocks, like:
try:
raise A()
except A:
raise B()
except B:
print 'Did we get here?'
This is legal and well-defined in Python. If try/except/finally was
removed it seems like multiple except blocks should have been removed
too--the behavior of one is as obvious as the other.
[Joshua Marshall] Why is this not an argument
'finally' wasn't removed based on "an argument", it was removed based
on negative feedback from real experience. What you give here
certainly is "an argument", but this wasn't an argument-based
decision.
for disallowing multiple except blocks, like:>
try: raise A() except A: raise B() except B: print 'Did we get here?'
Because there's no evidence that anyone is confused by this in
practice. There was ample evidence that many people were confused in
practice when a 'finally' clause was allowed too.
This is legal and well-defined in Python. If try/except/finally was removed it seems like multiple except blocks should have been removed too--the behavior of one is as obvious as the other.
So you say, but experience said otherwise. You can speculate about
why if you want to, but it's a fact -- for whatever reason, Python
programmers in real life are not confused by multiple 'except' blocks,
but were confused about the semantics of allowing 'finally' too at the
same level. No amount of argument can change that -- it was an
observation, not a deduction.
Joshua Marshall wrote: Why is this not an argument for disallowing multiple except blocks, like:
try: raise A() except A: raise B() except B: print 'Did we get here?'
This is legal and well-defined in Python. If try/except/finally was removed it seems like multiple except blocks should have been removed too--the behavior of one is as obvious as the other.
I'd like to note that, in this case, exactly one of the except blocks
gets executed. If an exception is raised within one of the branches, it
doesn't get caught by later branches.
In the 'finally' case, it's unclear whether it should catch such a
secondary exception or not. On the one hand, we have the established
precedent that an exception within an exception handler goes up to the
caller. On the other hand, we have the expectation that 'finally'
should always be executed when leaving the specified code block. But
which block is being specified -- just the 'try' section, or all of the
'except' clauses as well? Syntactically, it seems that try-clause-only
should be the correct answer, but including all of the except clauses
would be the most common desire...
Given the different semantics of finally vs except, I can certainly see
a *lot* of room for confusion.
Jeff Shannon
Technician/Programmer
Credit International This discussion thread is closed Replies have been disabled for this discussion. Similar topics
13 posts
views
Thread by KefX |
last post: by
|
11 posts
views
Thread by Pohihihi |
last post: by
|
2 posts
views
Thread by Abubakar |
last post: by
|
3 posts
views
Thread by WebBuilder451 |
last post: by
|
13 posts
views
Thread by Woody Splawn |
last post: by
|
20 posts
views
Thread by Woody Splawn |
last post: by
|
7 posts
views
Thread by Sean Kirkpatrick |
last post: by
|
32 posts
views
Thread by cj |
last post: by
|
3 posts
views
Thread by Jeff |
last post: by
| | | | | | | | | | |