Recommendations (or best practices) to define functions (or methods)

V

vizcayno

Hello:
Need your help in the "correct" definition of the next function. If
necessary, I would like to know about a web site or documentation that
tells me about best practices in defining functions, especially for
those that consider the error exceptions management.
I have the next alternatives but I think there are better:

Alternative 1:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
return e
return 1

Seems a good solution but the function is not returning an uniform
type, should the code that receives the function result decides the
error display according of datatype? If I do this in C# I think I will
have problems.


Alternative 2:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
return 0, e # or return (0,e.message)
return 1, "ok" # or return (1, "ok")
Sounds good, but seems forced. When doing return 1, "ok" I am doing
redundancy and I have problems with the type (e is exception type and
"ok" is string).


Alternative 3:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
print "ERROR:", e
return 0
return 1

It solves the problem of alternative 1 and 2, but the print keyword
would have problems if the function is called from an WEB or GUI
application and, because there are plans to convert print into a
function in py3k.


Alternative 4:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
print >> logerr, e.message
return 0
return 1

Seems a good solution but I should always be persuaded to have an open
global file (logerr) when invoking this function; otherwise code will
generate another error. The function is not totally independent.I think
I would be in the same situation when using the "logging" battery.

Thanks for your attention.

Regards,
 
G

George Sakkis

vizcayno said:
Hello:
Need your help in the "correct" definition of the next function. If
necessary, I would like to know about a web site or documentation that
tells me about best practices in defining functions, especially for
those that consider the error exceptions management.
I have the next alternatives but I think there are better:

Alternative 1:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
return e
return 1

Seems a good solution but the function is not returning an uniform
type, should the code that receives the function result decides the
error display according of datatype? If I do this in C# I think I will
have problems.


Alternative 2:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
return 0, e # or return (0,e.message)
return 1, "ok" # or return (1, "ok")
Sounds good, but seems forced. When doing return 1, "ok" I am doing
redundancy and I have problems with the type (e is exception type and
"ok" is string).


Alternative 3:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
print "ERROR:", e
return 0
return 1

It solves the problem of alternative 1 and 2, but the print keyword
would have problems if the function is called from an WEB or GUI
application and, because there are plans to convert print into a
function in py3k.


Alternative 4:
=============
def ExecuteSQL(cmdSQL, cursor):
try:
cursor.execute(cmdSQL)
except Exception, e:
print >> logerr, e.message
return 0
return 1

Seems a good solution but I should always be persuaded to have an open
global file (logerr) when invoking this function; otherwise code will
generate another error. The function is not totally independent.I think
I would be in the same situation when using the "logging" battery.

Thanks for your attention.

Regards,

My vote goes to None Of The Above. In neither alternative you actually
do anything useful with the exception other than reporting it in some
ad-hoc way. If that's all you can and/or want to do with it (i.e. no
error recovery of some sort), the typical thing to do is nothing; just
let it propagate up the call stack until the appropriate level. This
might be the console, a GUI, a logfile, an automatically sent email or
any combination of these or more. If it's a programmer's error (aka
bug), it should propagate all the way up and end in printing the stack
trace.

The bottom line is, it's simply not this function's (ExecuteSQL) job to
deal with the error, so it shouldn't. Most important, returning an
error or status code is rarely (if ever) desirable or necessary in
Python; that's what exceptions are for.

George
 
?

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

vizcayno said:
Need your help in the "correct" definition of the next function. If
necessary, I would like to know about a web site or documentation that
tells me about best practices in defining functions, especially for
those that consider the error exceptions management.

I agree with George Sakkis' remarks. The best way to define this function is

def ExecuteSQL(cmdSQL, cursor):
return cursor.execute(cmdSQL)

If this raises an exception, it likely means there is something
wrong with the SQL statement. The program should abort, and the
developer should correct it.

Regards,
Martin
 
F

Frank Millman

Martin said:
I agree with George Sakkis' remarks. The best way to define this function is

def ExecuteSQL(cmdSQL, cursor):
return cursor.execute(cmdSQL)

If this raises an exception, it likely means there is something
wrong with the SQL statement. The program should abort, and the
developer should correct it.

Regards,
Martin

With respect, I can offer a counter-argument.

I have a multi-user server program, with a connection to a database,
servicing multiple requests from connected clients.

The clients are 'thin' - the business logic resides on the server - so
when a client selects an option, the server imports the appropriate
module and executes it. If that includes a SQL command, the server
connects to the database, executes the command, and returns the result
to the client.

If there is something wrong with the SQL statement, I do not want to
crash the server, I want to notify the client that there was something
wrong, so that the offending module can be corrected and reloaded.

Frank Millman
 
?

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

Frank said:
If there is something wrong with the SQL statement, I do not want to
crash the server, I want to notify the client that there was something
wrong, so that the offending module can be corrected and reloaded.

Right. In a distributed system, you should propagate the error (in some
form) to the client.

Then the question is what the best form is: IMO, you should keep as
much information as possible. This means you either return the Python
exception to the client, to be re-raised on the client side, or you
log the exception on the server side, and just return to the client
the information that the full error message has been logged.

In any case: this should happen on the middleware layer, i.e. the place
that does the communication. Wrt. the OP's code, I still maintain that
all of his approaches to "silence" the exception are flawed. Exception
handling should either recover from the error (e.g. by adjusting the
environment, then retrying) or abort the execution. In a distributed
case, "abort the execution" may not mean "terminate the program", but
instead "immediately abort execution of the current request and return
an error to the client".

Regards,
Martin
 
D

Diez B. Roggisch

vizcayno said:
Hello:
Need your help in the "correct" definition of the next function. If
necessary, I would like to know about a web site or documentation that
tells me about best practices in defining functions, especially for
those that consider the error exceptions management.
I have the next alternatives but I think there are better:

<snip/>

IMHO none of them is good. Python has exceptions. Use them. There is no
need to awkwardly communicate error conditions using return-values. Use
return values to return values. Use exceptions in case of errors.

Diez
 
V

vizcayno

Martin v. Löwis ha escrito:
I agree with George Sakkis' remarks. The best way to define this function is

def ExecuteSQL(cmdSQL, cursor):
return cursor.execute(cmdSQL)

If this raises an exception, it likely means there is something
wrong with the SQL statement. The program should abort, and the
developer should correct it.

Regards,
Martin

Martin:
Thanks for your indications.
However, what happens when the error is due to data error. Or when the
program is reading many files to save data into a database and one or
two files have problems with data format. I would like to keep the
program running (using exception in a controlled way) for the remaining
good files and prepare a log about the failed files. How to keep the
same function for a program that runs in batch, or on-line or in the
web? Giving the simple example I put, I would like to find more
guidelines.
Thanks.
 
V

vizcayno

Diez B. Roggisch ha escrito:
<snip/>

IMHO none of them is good. Python has exceptions. Use them. There is no
need to awkwardly communicate error conditions using return-values. Use
return values to return values. Use exceptions in case of errors.

Diez

Diez, in that case I woul prefer not to use exceptions and wait for
Python to abort itself and wait to see the message it issues.
 
V

vizcayno

Diez B. Roggisch ha escrito:
<snip/>

IMHO none of them is good. Python has exceptions. Use them. There is no
need to awkwardly communicate error conditions using return-values. Use
return values to return values. Use exceptions in case of errors.

Diez

Diez, in that case I woul prefer not to use exceptions and wait for
Python to abort itself and wait to see the message it issues.
 
G

Gabriel Genellina

However, what happens when the error is due to data error. Or when the
program is reading many files to save data into a database and one or
two files have problems with data format. I would like to keep the
program running (using exception in a controlled way) for the remaining
good files and prepare a log about the failed files. How to keep the
same function for a program that runs in batch, or on-line or in the
web? Giving the simple example I put, I would like to find more
guidelines.

Deal with the exception at a higher level. In your example, you have
some files to be processed:

for fname in filenames:
do_something_with(fname)

==>

for fname in filenames:
try:
do_something_with(fname)
except StandardError, E:
log_error(E)


--
Gabriel Genellina
Softlab SRL






__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas
 
V

vizcayno

Thank you for your guidelines and for changing my mind. I am trying to
do my best in generating good code and, in that attempt ... I only know
that nothing know.
Regards.
 
B

Bruno Desthuilliers

vizcayno a écrit :
Hello:
Need your help in the "correct" definition of the next function. If
necessary, I would like to know about a web site or documentation that
tells me about best practices in defining functions, especially for
those that consider the error exceptions management.
I have the next alternatives but I think there are better:

Alternative 1:
=============
def ExecuteSQL(cmdSQL, cursor):

The recommended naming scheme is all_lower for functions, methods and
variables, CamelCase for classes and ALL_UPPER for pseudo-constants.
try:
cursor.execute(cmdSQL)
except Exception, e:
return e
return 1

Seems a good solution

Err... The whole point of exceptions is to avoid using return values as
error code. Your code would be *much* better without this braindead
(sorry) "exception handling":

def execute_sql(sql, cursor):
cursor.execute(sql)

And now, since it's obvious that it's just a totally useless function
call. So just ditch this function, and just call cursor.execute directly !-)

(snip other examples of how to not handle exceptions...)
 
D

Diez B. Roggisch

vizcayno said:
Diez B. Roggisch ha escrito:


Diez, in that case I woul prefer not to use exceptions and wait for
Python to abort itself and wait to see the message it issues.

You are not making sense here - to me at last.

If you don't handle the exceptions, exactly what you seem to want will
happen - you will see the interpreter stop, and why.

Handling errors in a graceful way can't be done by a standardized way,
as you seem to want. It depends to much on what the actual code is
doing. Sometimes an abort is necessary, sometimes you can continue
working - but it all depends on what your actual usecase is, on a very
detailed level.

All you did was to take the unpythonic (and un-javaic and un-C#ic) road
to transform an exception to a returncode. But that has nothing to do
with actually _dealing_ with the error. Instead, it just makes it more
likely that you _don't_ deal with it, as a return-code evaluation might
be more easily forgotten, and turn out with a program that will be
error-prone, as it continues to run even when the preconditions for
pieces of code aren't met anymore.


Diez
 
F

Frank Millman

Diez said:
If you don't handle the exceptions, exactly what you seem to want will
happen - you will see the interpreter stop, and why.

All you did was to take the unpythonic (and un-javaic and un-C#ic) road
to transform an exception to a returncode. But that has nothing to do
with actually _dealing_ with the error. Instead, it just makes it more
likely that you _don't_ deal with it, as a return-code evaluation might
be more easily forgotten, and turn out with a program that will be
error-prone, as it continues to run even when the preconditions for
pieces of code aren't met anymore.

I absolutely agree with this. I will describe my particular experience,
in the hope that it will make it clear to vizcayno just how important
this is.

My app does a lot of database/user interaction. I read a row from the
database, display it to the user, allow the user to change the value of
various columns, and write it back again.

I had a routine which validated whether the user input was acceptable
based on various business rules. If the input was good, it would update
the internal value of the column and return True, else it would not
update the value and return False. I would check the return code and,
if False, display an error message and reprompt the user for input.
What could go wrong with that?

Well, during the execution of the program, I also update the values of
various columns programatically. I call the same routine, but I did not
check the return code, as it would add a lot of extra checks, and as it
was program generated it would always pass a valid value.

This was true 99.9% of the time, but occasionally, due to a program
error, I would pass an invalid value. The validation routine correctly
did not update the internal value, and returned False, but as I did not
check this I continued merrily on my way. Later on when I found that
the value had not changed, it took me a long time to trace the error.

I suffered like this for quite a long time before the light bulb went
off, based on a thread on c.l.py. Now I do it like this.

The validation routine performs the same function, but instead of
returning True/False, it raises ValueError if the check fails. Where I
previously tested the return code, I now have a try/except clause,
which does the same as before.

The big difference is, what happens if I programmatically pass an
invalid value? Where before, the error would pass silently, now my
program aborts, with the traceback, which is exactly what I want.

Frank Millman
 

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

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top