Regarding exception handling

  • Thread starter Aggelos I. Orfanakos
  • Start date
A

Aggelos I. Orfanakos

Hello.

In a program, I want to ensure that a socket closes (so I use try ...
finally), but I also want to catch/handle a socket exception. This is
what I have done:

try:
try:
s = ... # socket opens

# various code ...
except socket.error, x:
# exception handling
finally:
s.close() # socket closes

Is there a more "elegant" or "proper" way to do this? Or the above code
is OK?

Thanks in advance.
 
B

beliavsky

Aggelos said:
(I don't know why, but indentation was not preserved once I posted.)

This problem and its possible solutions was discussed here in the
thread "OT: spacing of code in Google Groups".
 
A

Aggelos I. Orfanakos

Thanks. This should now be OK:

#try:
# try:
# s = ... # socket opens
#
# # various code ...
# except socket.error, x:
# # exception handling
#finally:
# s.close() # socket closes
 
D

Dan Perl

Aggelos I. Orfanakos said:
Thanks. This should now be OK:

#try:
# try:
# s = ... # socket opens
#
# # various code ...
# except socket.error, x:
# # exception handling
#finally:
# s.close() # socket closes

Why the nested try's? If I understand your intention correctly this should
do the same thing:

try:
s = ... # socket opens
# various code ...
except socket.error, x:
# exception handling
s.close() # socket closes

You would need the try-finally statement only if you expect it to handle
other exceptions than socket.error or if the socket.error is re-raised in
the "except" clause. Otherwise, the try-finally statement is redundant
because no socket.error are getting out of the try-except statement.

Dan
 
B

Bryan

Dan said:
Why the nested try's? If I understand your intention correctly this should
do the same thing:

try:
s = ... # socket opens
# various code ...
except socket.error, x:
# exception handling
s.close() # socket closes

You would need the try-finally statement only if you expect it to handle
other exceptions than socket.error or if the socket.error is re-raised in
the "except" clause. Otherwise, the try-finally statement is redundant
because no socket.error are getting out of the try-except statement.

Dan

i always use the try/finally statement with resources, but in a slightly
different way than the above two examples:

s = ... # socket opens
try:
# various code ...
finally:
s.close()


or, if i want to handle the socket.error if s gets successfully bound,


s = ... # socket opens
try:
try:
# various code
except socket.error e:
# exception handling
finally:
s.close()

i disagree with the statement:

"You would need the try-finally statement only if you expect it to handle other
exceptions than socket.error or if the socket.error is re-raised in the "except"
clause. Otherwise, the try-finally statement is redundant because no
socket.error are getting out of the try-except statement."

IMO, that is not the reason for the try/finally statement and it is not
redundant. the try/finally statement guarantees the resource is closed and the
try/finally statement only gets executed if and only if the opening of the
resource doesn't raise an exception. it has nothing to do with exception handling.

in the previous 2 examples s = ... was placed inside the try/finally, but if an
exception occures and s doesn't get bound to an object, then s.close() in both
examples will raise a NameError on s.

bryan
 
A

Aggelos I. Orfanakos

I need it because the "various code" may raise other exceptions (not
related to sockets). In such case, the "except socket.error, x:" won't
catch it, but thanks to the "finally:", it is sure that the socket will
close.
 
A

Aggelos I. Orfanakos

Good point, but with your way, if "s = ... # socket opens" fails, then
nothing will catch it. What I usually do is what I wrote above (place
it below the 2nd try), and when attempting to close it, first use an if
like: "if locals().has_key('s'):".
 
D

Dan Perl

Bryan said:
IMO, that is not the reason for the try/finally statement and it is not
redundant. the try/finally statement guarantees the resource is closed
and the try/finally statement only gets executed if and only if the
opening of the resource doesn't raise an exception. it has nothing to do
with exception handling.

But IMO, try-finally is meant to be used only if the block in the try clause
may raise exceptions. Here is an example that shows what I meant:
s = ... # socket opens
try:
a = 1
finally:
s.close()

works perfectly the same as:
s = ... # socket opens
a = 1
s.close()

The try-finally statement does not "handle" the exception, but it makes
sense only if exceptions are possible. There is no point in enclosing "a =
1" in any kind of try statement.

According to a following posting from Angelos he did expect some other
exceptions than socket.error and hence the nested try's. To my defence
though, I put in a disclaimer for that case in my initial posting.
in the previous 2 examples s = ... was placed inside the try/finally, but
if an exception occures and s doesn't get bound to an object, then
s.close() in both examples will raise a NameError on s.

That is a very good point. I missed it.

Dan
 
D

Dan Perl

Aggelos I. Orfanakos said:
Good point, but with your way, if "s = ... # socket opens" fails, then
nothing will catch it. What I usually do is what I wrote above (place
it below the 2nd try), and when attempting to close it, first use an if
like: "if locals().has_key('s'):".

Then how about:
try:
s = ... # socket opens
try:
# various code ...
finally:
s.close() # socket closes
except socket.error, x:
# exception handling

This handles all the socket exceptions in one shot. The only problem is
that different problems may have to be handled differently. For instance,
you may need to handle a transmission that failed in the middle differently
than a failure to open the socket.

Dan
 
B

Bryan

Dan said:
But IMO, try-finally is meant to be used only if the block in the try clause
may raise exceptions. Here is an example that shows what I meant:
s = ... # socket opens
try:
a = 1
finally:
s.close()

works perfectly the same as:
s = ... # socket opens
a = 1
s.close()

the above is not the same. make the a = ... raise an exception and you'll see
the difference.

s = ... #
a = 1/0
s.close()

as you can see, s.close() will never be called. also, in this example, i
intentionally didn't put the extra try/except around the try/finally statement.
usually i let an exception caused by s = ... to bubble up to some level that
knows how to handle that error. we are talking about a resource here and in my
experience, these low level functions (below the UI or management layer) don't
know how to or shouldn't handle resources that can't be opened.

bryan
 
F

Fredrik Lundh

the above is not the same. make the a = ... raise an exception and you'll see the difference.

s = ... #
a = 1/0
s.close()

as you can see, s.close() will never be called. also, in this example, i intentionally didn't put
the extra try/except around the try/finally statement.

file handles and sockets are closed when the objects are garbage collected.
under CPython, they're usually closed when they go out of scope.

using try/finally on files and sockets are usually overkill.

</F>
 
B

Bryan

Fredrik said:
file handles and sockets are closed when the objects are garbage collected.
under CPython, they're usually closed when they go out of scope.

using try/finally on files and sockets are usually overkill.

</F>

i was trying to be generic and use the term resource. i know you are correct
about file handles and sockets. there are other resources that don't behave so
nicely. i'm currently using a third party module that will crash python (the
entire interpreter GPF's) if you don't explicitly close the resource before your
python script exits. other times, depending on a variable to go out of scope to
have a resource automically close itself is not practical. or sometimes you
want a resource to be closed, but still hold on to the reference. so, i don't
feel as strongly as you do that try/finally on even files and socks are
overkill. of course on small scripts, i don't use try/finally or close() either :)

bryan
 
A

Aggelos I. Orfanakos

Coming from C, I think that it's generally a good programming practice
to make sure everything you create, closes; whether it's about a socket
or a file. This may not be the case with Python though. To be honest,
leaving this task to the garbage collector doesn't sound like a good
idea to me (since the language gives you the means to do it yourself).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top