Configure this Python statement without breaking readability

I'm still pretty new to Python, so I'm trying to figure out how to do this and need help.

I am using return codes to make sure my internal functions return successfully. For example (from internal library functions):

result = some_function(arg1,arg2)
if result != OK: return result

      

or (from the main script level):

result = some_function(arg1,arg2)
if result != OK: abort_on_error("Could not complete 'some_function': %s" % messages(result))

      

Can I get this down to one line without making it unreadable?

EDIT: Some people admit that exceptions might be the best choice. I wanted to keep exceptions only for a very "exceptional" capture script. Return codes can be expected to fail at times, and I thought it was generally a bad practice to use exceptions for this scenario.

+2


source to share


5 answers


Sounds like you want something like ..

if result = some_function(arg1, arg2):
    return result

      

This is very intentionally not possible in Python. It is too common a typo to write if a = b

instead if a == b

and allow this mixing with flow control. If necessary, split it into two lines:

x = some_function()
if x:
    print "Function returned True"

      

A more practical example of this is ...

result = re.match("a", "b")
if result:
   print result.groups()

      

(or rather, you should do if result is not None:

in this case, although it works)

In your specific case ("to make sure my inner functions return successfully"), it looks like you should be using exceptions. If everything is ok, just return whatever you want. If something goes wrong, throw an exception.

Exceptions in Python are not like many other languages ​​- for example, they are used for internal flow control (like StopIteration exception)

I would prefer the following much more Pythonic than using return codes:

#!/usr/bin/env python2.6
def some_function(arg1, arg2):
    if arg1 + arg2 > 5:
        return "some data for you"
    else:
        raise ValueError("Could not complete, arg1+arg2 was too small")

      



Then you can call the function in one line:

return some_function(3, 2)

      

This either returns a value or throws an exception, which you could handle the exception somewhere reasonable:

def main():
    try:
        result = some_function(3, 5)
    except ValueError, errormsg:
        print errormsg
        sys.exit(1)
    else:
        print "Everything is perfect, the result was {0}".format(result)

      

Or, if this case is actually a bug, just stop the application with a nice stack trace.

Yes, it is much longer than one line, but Python's idea is brevity but clarity and readability.

Basically, if the function can no longer continue, throw an exception. Refer to this exception where you can recover from the problem, or present the user with an error message .. unless you are writing a library, in which case the exception should trigger the stack for the calling code

Or in the form of a poem:

$ python -m this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than * right * now.
If the implementation is hard to explain, it a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea - let do more of those!

Finally, it might be worth reading "PEP 8" , the Python style guide. It can answer some of your questions, such as "Are one-line expressions pythons?"

Component statements (multiple statements on one line) are usually discouraged.

Yes:

if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three()

      

Rather not:

if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()

      

+3


source


Could you use exceptions to indicate failure rather than return codes? Then most of your operators if result != OK:

will simply disappear.



+10


source


pythonic :

An idea or piece of code that closely follows the most common idioms of the Python language, rather than implementing code using concepts common to other languages. [...]

Doesn't imply writing liners!

+3


source


If you insist on not using exceptions, then I would write two lines (one line would be too long here):

res = some_function(arg1, arg2)
return res if res != OK else ...

      

By the way, I recommend that you come up with some static type of values ​​returned by your function (despite being dynamically typed in Python). For example, you can return "either int

or None

". You can put such a description in the docstring.

If you have error values int

and int

codes, you can tell them apart by introducing an error class:

class ErrorCode(int): pass

      

and then check if the result matches isinstance

ErrorCode

.

+1


source


In addition to exceptions, using a decorator is a good solution to this problem:

# Create a function that creates a decorator given a value to fail on...
def fail_unless(ok_val):
   def _fail_unless(f):
       def g(*args, **kwargs):
           val = f(*args, **kwargs)
           if val != ok_val:
               print 'CALLING abort_on_error...'
           else:
               return val
       return g
   return _fail_unless


# Now you can use the decorator on any function you'd like to fail 
@fail_unless('OK')
def no_negatives(n):
    if n < 0:
        return 'UH OH!'
    else:
        return 'OK'

      

On practice:

>>> no_negatives(9)
'OK'
>>> no_negatives(0)
'OK'
>>> no_negatives(-1)
'CALLING abort_on_error...'

      

I know the syntax defining fail_unless

is a little tricky if you're not used to decorators and function closures, but the app is fail_unless()

pretty good isn't?

-1


source







All Articles