Confused compare function :)

Chris Angelico rosuav at gmail.com
Thu Dec 6 08:47:16 EST 2012


On Fri, Dec 7, 2012 at 12:32 AM, Hans Mulder <hansmu at xs4all.nl> wrote:
> On 6/12/12 12:55:16, peter wrote:
>> Is perfectly right to use try catch for a flow control.
>> Just think in something more complex like this.
>>
>>    try:
>>             self._conn = MySQLdb.connect(host=host,
>>                 user=user,
>>                 passwd=passwd,
>>                 db=db)
>>     except:
>>             logging.info("Error de conexion con la base de datos")
>>             inform(subject = 'Db down on app %s' % app, body=sbody)
>
> This is an example of the sort of incorrect code you
> should try to avoid.  An improved version is:
>
>    self._conn = MySQLdb.connect(host=host,
>                 user=user,
>                 passwd=passwd,
>                 db=db)
>
> By not catching the exception, you're allowing the
> Python interpreter to report what the problem was,
> for example "Keyboard interrupt" or "Access denied".
>
> By report "DB down" when there is no reason to assume
> that that is the problem, you're confusing the user.

The problem with the original example is that it has a bare except,
which will catch too much. Call it an oversimplified example, perhaps
:) By not catching the exception, you doom your entire script to
abort. What Steven called felicide is catching exceptions *and
immediately exiting*, which offers little benefit over just letting
the exception propagate up.

>> Or maybe something like this.
>>
>> try:
>>             cursor.execute(sqli, data)
>>             self._conn.commit()
>> except:
>>             try:
>>                 self._conn.rollback()
>>                 cursor.execute(sqli, data)
>>                 self._conn.commit()
>>             except Exception, e:
>>                 pass
>>                 # print e
>>                 # logging.info('ERROR en la insercion %s' % e)
>
> This is another example of what not to do.  Even the
> commented-out print statement loses information, viz.
> the traceback.
>
> If you leave out the try/except, then more accurate
> information will be printed, and a programmer who needs
> to fix the problem, can run the code under the debugger
> and it will automatically stop at the point where the
> uncaught exception is raised.  That's much easier than
> having to set breakpoints at all the "except Exception:"
> clauses in a typical chunk of hard-to-maintain code.

Again, oversimplified example. If this were real code, I'd criticize
the bare except (and the "except Exception", which has the same
problem).

> Context managers were invented to make it easier to do
> this sort of thing correctly.  For example:
>
>     with sqlite3.connect(dbpath) as connection:
>         connection.cursor().execute(sqli, data)
>
> If the flow reaches the end of the "with" command,
> the connection object will self.commit() automatically.
> If an exception is raised, the connection object will
> self.rollback() automatically.  No try/except required.
>
> This is shorter, and much easier to get right.

But it does something completely different. The original code's logic
is: Try the query, then commit. If that fails, roll back and have
another shot at it. This is dangerous if there could have been other
statements in the transaction (they won't be retried), but otherwise,
it's a reasonable way of dealing with serialization failures. It has
its risks, of course, but it's not meant to be a demo of database
code, it's a demo of try/except.

>> This is pretty dumb, but is a valid example, on what you can
>> do with try catch
>
> It is an unfortunate fact of life that you can write code
> that is hard to maintain.  The fact that you *can* do this,
> does not mean that you should.

Agreed. However, the mere presence of try/except does not make code
unmaintainable, nor is it a strong indication that the code already
was.

ChrisA



More information about the Python-list mailing list