Re: Bare Excepts

6 views
Skip to first unread message

Jean-Michel Pichavant

unread,
Dec 30, 2009, 8:04:37 AM12/30/09
to Victor Subervi, python-list
Victor Subervi wrote:
> Hi;
> I'll trouble-shoot bare excepts as I work on new code. I'll
> trouble-shoot the others that don't (seem to) cause problems later.
> Here's a new one:
>
> for optionsStore, storeOptions in ourOptions().iteritems():
> if store == optionsStore:
> for option in storeOptions:
> try:
> fromForm = form.getfirst(option)
> try:
> fromForm, junk = string.split(fromForm, ':')
> except:
> pass # This is only an expedient to split options that
> have a colon in them, such as the colors
> fromForm = string.replace(fromForm, '-', '')
> sql = 'select "%s" from %s%s t join %s p where p.ID=t.ID;'
> % (fromForm, store, (option[0].upper() + option[1:]), store)
> # print sql
> cursor.execute(sql)
> try:
> optionsPrices += cursor.fetchone()[0]
> except TypeError:
> pass # There is no options price for this.
> except:
> raise
>
> If there are no values entered into table (in this case
> "productsSizes") for the given product ID, then "optionsPrices" should
> not be added unto. Am I doing this correctly? Or is there a better way
> than capturing ALL TypeErrors?
> TIA,
> beno
Hello,

Do not use the 'try except' clause when 'if then' can perfectly handle
the case.

i.e.
try:
fromForm, junk = string.split(fromForm, ':')
except:
pass # This is only an expedient to split options that
have a colon in them, such as the colors

would be better written

# This is only an expedient to split options that have a colon in them,
such as the colors
if ':' in fromForm:
fromForm, junk = fromForm.split(':')

or

fromForm = fromForm.split(':')[0]


Anyway, you should definitely use a coding rule checker, like pylint or
pyckeck. It would sometimes point you into the correct direction. For
instance, pylint will tell you that except: pass is often (not always) a
clue for bad design/pattern and issue warnings for it.

In a more general manner, use try blocks when the code can throw
exceptions upon condition you do not control. When you know about the
conditions, use the if statement.

No:

a = None
try:
a.split()
except AttributeError:
pass


Yes:

a = None
if a:
a.split()

Exception are required in the following example:

try:
main()
except KeyboardInterrupt:
print 'interrupted by user'

Cheers,

JM

Jean-Michel Pichavant

unread,
Dec 30, 2009, 8:23:01 AM12/30/09
to Victor Subervi, python-list
Victor Subervi wrote:

> On Wed, Dec 30, 2009 at 9:09 AM, Victor Subervi
> <victor...@gmail.com <mailto:victor...@gmail.com>> wrote:
>
>
> Anyway, you should definitely use a coding rule checker, like
> pylint or pyckeck. It would sometimes point you into the correct
> direction. For instance, pylint will tell you that except: pass is
> often (not always) a clue for bad design/pattern and issue
> warnings for it.
>
> How about this:
>
> try:
> id = form.getfirst('id')
> sql = 'update %s set ProdID="%s" Quantity="%s" %s where
> ID="%s";' % (tmpTable, prodid, quantity, sqlUpdateMiddle, id)
> cursor.execute(sql)
> db.commit()
> except:
> raise
>
> How does one get around sql calls that fail?
> beno
>
Rule N� 1:
put the minimum code in try blocks

Rule N�2:
dont use BARE EXCEPT, or you'll piss off MRAB for good :o). Beside from
kidding, don't use bare except.

id = form.getfirst('id')
sql = 'update %s set ProdID="%s" Quantity="%s" %s where ID="%s";' %
(tmpTable, prodid, quantity, sqlUpdateMiddle, id)
try:
cursor.execute(sql)
db.commit()
except NAME_OF_THE_EXCEPTION :
raise # reraising without doing anything else is meaninless, you
could remove the try block


In your example you must lookt at your sql module documentation to know
which kind of exception it can throw.

JM

samwyse

unread,
Dec 30, 2009, 9:11:45 AM12/30/09
to
On Dec 30, 7:23 am, Jean-Michel Pichavant <jeanmic...@sequans.com>
wrote:

> Rule N°2:
> dont use BARE EXCEPT, or you'll piss off MRAB for good :o). Beside from
> kidding, don't use bare except.

I inherited some code that used bare excepts *everywhere*. There were
about 4K lines of code, IIRC, and I think that they were more except
clauses than elses. Eventually, I used sed to add a print_exc() after
each one, just so I could figure out what the expected exceptions
were. It was so bad that I seriously considered writing a program
just to parse all the tracebacks from my instrumented version and then
revise the source code for me, but I didn't want to accidentally miss
any "real" errors.

Steve Holden

unread,
Dec 30, 2009, 11:23:37 AM12/30/09
to pytho...@python.org
Victor Subervi wrote:
> On Wed, Dec 30, 2009 at 9:23 AM, Jean-Michel Pichavant
[...]

> In your example you must lookt at your sql module documentation to
> know which kind of exception it can throw.
>
>
> Or just throw the exception once and grab it. Okay, thanks ;)
> beno
>
Now *that* is using your brain. Good thinking!

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/

Ben Finney

unread,
Dec 30, 2009, 3:29:58 PM12/30/09
to
samwyse <sam...@gmail.com> writes:

> I inherited some code that used bare excepts *everywhere*. There were
> about 4K lines of code, IIRC, and I think that they were more except
> clauses than elses.

Visual Basic programmers will learn how to write “ON ERROR RESUME NEXT”
<URL:http://www.vbinfozine.com/a_onerror.shtml> in any language put
before them.

--
\ “I'm a born-again atheist.” —Gore Vidal |
`\ |
_o__) |
Ben Finney

Steve Holden

unread,
Dec 30, 2009, 11:00:09 PM12/30/09
to pytho...@python.org
Victor Subervi wrote:
> On Wed, Dec 30, 2009 at 3:29 PM, Ben Finney <ben+p...@benfinney.id.au
> <mailto:ben%2Bpy...@benfinney.id.au>> wrote:

>
> samwyse <sam...@gmail.com <mailto:sam...@gmail.com>> writes:
>
> > I inherited some code that used bare excepts *everywhere*. There were
> > about 4K lines of code, IIRC, and I think that they were more except
> > clauses than elses.
>
> Visual Basic programmers will learn how to write �ON ERROR RESUME NEXT�

> <URL:http://www.vbinfozine.com/a_onerror.shtml> in any language put
> before them.
>
>
> Yet another example of children belittling others to make themselves
> feel important.
> beno
>
So turn the mirror in yourself, and ask yourself why you just made that
comment? It takes all sorts to make a world, and we all need to run
along. Surely it's easier to ignore that kind of stuff than to
perpetuate it?

myle

unread,
Jan 1, 2010, 6:27:57 PM1/1/10
to
Why we should prefer ``if: ...'' over a ``try: ... except something:
pass'' block?
In http://wiki.python.org/moin/PythonSpeed/PerformanceTips#InitializingDictionaryElements
it is stated that a try catch block is faster if more often no
exception occurs.

Happy new year,
Dimitris Leventeas

Steven D'Aprano

unread,
Jan 2, 2010, 5:42:17 AM1/2/10
to
On Fri, 01 Jan 2010 15:27:57 -0800, myle wrote:

> Why we should prefer ``if: ...'' over a ``try: ... except something:
> pass'' block?

We shouldn't, not in general.

Often, the if test is just as expensive as actually doing it. E.g.:

if x in mylist:
position = mylist.index(x)
else:
do_something()

has to search the list twice, first to see if x is there, then search it
again to return the index. That does double the work needed. A better way
is:

try:
position = mylist.index(x)
except ValueError:
do_something()

unless you expect that x is often missing: setting up the try block is
much faster than the test, but catching the exception is much, much
slower. So long as exceptions are rare, it is better to use the try
version (also known as "Better to ask forgiveness than permission"). But
if exceptions are common, it may be better to use the if version ("Look
before you leap").

The try version is also better whenever there could be a race condition.
For example, when opening a file, you might be tempted to do this:

if os.path.exists(filename):
f = open(filename, 'r')
text = f.read()
else:
print "file missing"

but that is dangerous in a multi-processing computer system (which nearly
all computers are these days). The problem is that in the fraction of a
second after you test that the file exists, some other process might come
along and delete it and the open call will then fail. So to be safe, you
have to do this:

if os.path.exists(filename):
try:
f = open(filename, 'r')
except IOError:
print "file missing"
else:
text = f.read()
else:
print "file missing"


But of course now the test is redundant, and all you really need is the
try...except block:

try:
f = open(filename, 'r')
except IOError:
print "file missing"
else:
text = f.read()


(Note: the above is still not entirely robust. For example, if you try to
read a file that you don't have permission to read, it wrongly reports it
is missing instead of a permissions error. To make this more robust, you
need to inspect the exception and check the error code.)

--
Steven

Lie Ryan

unread,
Jan 2, 2010, 9:10:51 AM1/2/10
to
On 1/2/2010 9:42 PM, Steven D'Aprano wrote:
> On Fri, 01 Jan 2010 15:27:57 -0800, myle wrote:
>
>> Why we should prefer ``if: ...'' over a ``try: ... except something:
>> pass'' block?
>
> We shouldn't, not in general.

One exception (pun intended) is if the try-block have a side effect that
is difficult to cleanup cleanly.

Aahz

unread,
Jan 2, 2010, 12:40:44 PM1/2/10
to
In article <034f1009$0$1277$c3e...@news.astraweb.com>,

OTOH, if you want to do something different depending on whether the file
exists, you need to use both approaches:

if os.path.exists(fname):
try:
f = open(fname, 'rb')
data = f.read()
f.close()
return data
except IOError:
logger.error("Can't read: %s", fname)
return ''
else:
try:
f = open(fname, 'wb')
f.write(data)
f.close()
except IOError:
logger.error("Can't write: %s", fname)
return None

(This is a somewhat stupid example strictly for illustration. A better
and more-elaborate example would be something like trying to copy a file
to fname and rename an existing file to '.bak' if it exists. The tricky
part would be trying to rename the '.bak' to fname if the copy fails.
And yes, that's exactly what some code I wrote a few days ago does.)
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

Weinberg's Second Law: If builders built buildings the way programmers wrote
programs, then the first woodpecker that came along would destroy civilization.

Steven D'Aprano

unread,
Jan 2, 2010, 7:30:03 PM1/2/10
to
On Sat, 02 Jan 2010 09:40:44 -0800, Aahz wrote:

> OTOH, if you want to do something different depending on whether the
> file exists, you need to use both approaches:
>
> if os.path.exists(fname):
> try:
> f = open(fname, 'rb')
> data = f.read()
> f.close()
> return data
> except IOError:
> logger.error("Can't read: %s", fname) return ''
> else:
> try:
> f = open(fname, 'wb')
> f.write(data)
> f.close()
> except IOError:
> logger.error("Can't write: %s", fname)
> return None

Unfortunately, this is still vulnerable to the same sort of race
condition I spoke about.

Even more unfortunately, I don't know that there is any fool-proof way of
avoiding such race conditions in general. Particularly the problem of
"open this file for writing only if it doesn't already exist".


> (This is a somewhat stupid example strictly for illustration. A better
> and more-elaborate example would be something like trying to copy a file
> to fname and rename an existing file to '.bak' if it exists. The tricky
> part would be trying to rename the '.bak' to fname if the copy fails.
> And yes, that's exactly what some code I wrote a few days ago does.)

Sounds interesting and useful. Would you care to share it with us, or to
publish it as a recipe?

--
Steven

Steven D'Aprano

unread,
Jan 2, 2010, 7:30:17 PM1/2/10
to

What if the "if ..." test has a side-effect? This is an argument against
side-effects, not against using exceptions.


But of course you are right, there are lots of good reasons for choosing
to use an if test rather than a try block, or vice versa. I would argue
that the try block is generally more Pythonic, and should be preferred,
but that doesn't mean that there aren't reasons for sometimes choosing
other strategies instead.


--
Steven

Dave Angel

unread,
Jan 2, 2010, 9:35:48 PM1/2/10
to Steven D'Aprano, pytho...@python.org
> <snip>
In Windows, there is a way to do it. It's just not exposed to the
Python built-in function open(). You use the CreateFile() function,
with /dwCreationDisposition/ of CREATE_NEW.

It's atomic, and fails politely if the file already exists.

No idea if Unix has a similar functionality.

DaveA


Aahz

unread,
Jan 14, 2010, 4:33:38 PM1/14/10
to
In article <034fd208$0$1277$c3e...@news.astraweb.com>,

Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> wrote:
>On Sat, 02 Jan 2010 09:40:44 -0800, Aahz wrote:
>>
>> OTOH, if you want to do something different depending on whether the
>> file exists, you need to use both approaches:
>>
>> if os.path.exists(fname):
>> try:
>> f = open(fname, 'rb')
>> data = f.read()
>> f.close()
>> return data
>> except IOError:
>> logger.error("Can't read: %s", fname) return ''
>> else:
>> try:
>> f = open(fname, 'wb')
>> f.write(data)
>> f.close()
>> except IOError:
>> logger.error("Can't write: %s", fname)
>> return None
>
>Unfortunately, this is still vulnerable to the same sort of race
>condition I spoke about.

True; nevertheless, my point remains that if you want to do something
different depending on whether the file exists, you must use both LBYL
and EAFP.

>Even more unfortunately, I don't know that there is any fool-proof way of
>avoiding such race conditions in general. Particularly the problem of
>"open this file for writing only if it doesn't already exist".

IIUC, you can lock files that don't exist.

>> (This is a somewhat stupid example strictly for illustration. A better
>> and more-elaborate example would be something like trying to copy a file
>> to fname and rename an existing file to '.bak' if it exists. The tricky
>> part would be trying to rename the '.bak' to fname if the copy fails.
>> And yes, that's exactly what some code I wrote a few days ago does.)
>
>Sounds interesting and useful. Would you care to share it with us, or to
>publish it as a recipe?

Unfortunately, it's a bit too tightly tied to some other stuff in the
code, plus I'll need to get permission from my bosses. We'll see.

"If you think it's expensive to hire a professional to do the job, wait
until you hire an amateur." --Red Adair

sjde...@yahoo.com

unread,
Jan 14, 2010, 6:36:59 PM1/14/10
to

It does. In Unix, you'd pass O_CREAT|O_EXCL to the open(2) system
call (O_CREAT means create a new file, O_EXCL means exclusive mode:
fail if the file exists already).

The python os.open interface looks suspiciously like the Unix system
call as far as invocation goes, but it wraps the Windows functionality
properly for the relevant flags. The following should basically work
on both OSes (though you'd want to specify a Windows filename, and
also set os.O_BINARY or os.O_TEXT as needed on Windows):

import os

def exclusive_open(fname):
rv = os.open(fname, os.O_RDWR|os.O_CREAT|os.O_EXCL)
return os.fdopen(rv)

first = exclusive_open("/tmp/test")
print "SUCCESS: ", first
second = exclusive_open("/tmp/test")
print "SUCCESS: ", second


Run that and you should get:
SUCCESS <open file '<fdopen>', mode 'r' at 0xb7f72c38>
Traceback (most recent call last):
File "testopen.py", line 9, in <module>
second = exclusive_open("/tmp/test")
File "testopen.py", line 4, in exclusive_open
rv = os.open(fname, os.O_RDWR|os.O_CREAT|os.O_EXCL)
OSError: [Errno 17] File exists: '/tmp/test'

Aahz

unread,
Jan 22, 2010, 4:52:34 PM1/22/10
to
In article <80c56956-f28e-47a3...@j19g2000yqk.googlegroups.com>,
sjde...@yahoo.com <sjde...@yahoo.com> wrote:

>On Jan 2, 9:35=A0pm, Dave Angel <da...@ieee.org> wrote:
>>
>> In Windows, there is a way to do it. It's just not exposed to the
>> Python built-in function open(). You use the CreateFile() function,
>> with /dwCreationDisposition/ of CREATE_NEW.
>>
>> It's atomic, and fails politely if the file already exists.
>>
>> No idea if Unix has a similar functionality.
>
>It does. In Unix, you'd pass O_CREAT|O_EXCL to the open(2) system
>call (O_CREAT means create a new file, O_EXCL means exclusive mode:
>fail if the file exists already).

Thanks!

import antigravity

Reply all
Reply to author
Forward
0 new messages