stylistic question -- optional return value

Bengt Richter bokr at oz.net
Mon Sep 2 06:58:46 CEST 2002


On Thu, 29 Aug 2002 13:37:26 GMT, Andrew Koenig <ark at research.att.com> wrote:

>Roy> It's also virtually always true that the real way to speed up a
>Roy> program is not code tweaking, but using better algorithms.
>
>Like most generalizations, this one is not always true.
>
>Remember, we're talking here about an interface decision, which
>means that changing it after the fact is difficult.  Moreover,
>this particular program is going to involve a large number of recursive
>function calls, every one of which will use this mechanism to pass
>information back to its caller.  In this case, therefore, the choice
>of interface will have a substantial effect on the execution speed
>of the whole program, and it will be difficult to change it later.
>
>In such circumstances, a factor of three is too much to ignore.  I am
>not saying that the faster interface is always the right one, but I am
>saying that when there's a large speed difference, and the decision
>will be difficult to change later, then there had better be a
>substantial argument in favor of the slower alternative.  Which
>I don't think there is in this case.
>
If added information is the exception (;-) rather than the rule, you might
want to consider using an exception to return the unusual bag of data.
try: is supposed to be low overhead, and the payoff is a clean main path
of excution, using the retval as-is normally, without having to test or
index into a tuple etc., and without having to pack a tuple for a normal
return value from the routine. You can define your own exception and raise it
with an arbitrary set of args, e.g.,

 >>> class MyExceptionalData(Exception):
 ...     pass
 ...
 >>> try:
 ...     raise MyExceptionalData('x value', 'optional y')
 ... except MyExceptionalData, mxd:
 ...     print mxd
 ...
 ('x value', 'optional y')
 >>> mxd
 <__main__.MyExceptionalData instance at 0x007A2460>
 >>> dir(mxd)
 ['__doc__', '__getitem__', '__init__', '__module__', '__str__', 'args']
 >>> mxd.args
 ('x value', 'optional y')
 >>> mxd[0]
 'x value'
 >>> mxd[1]
 'optional y'

You could also give your exception class an __init__ function to set
instance attributes and whatever else you'd like.

Anyway, your code might look something like

    try:                           # try overhead only
        x = foo()                  # use x knowing single return value assumption is ok
    except MyExceptionalData, e:
        x, y = e.args              # use x and y according to the exceptional situation

or alternatively

    try:                           # try overhead only
        x = foo()                  # use x knowing single return value assumption is ok
    except MyExceptionalData, e:
        x, y = e.args
        # use y here according to the exceptional situation
    # use x here either way
 
as opposed to something like

     x = foo()
     if x[1] is not sentinel:    # big index + test overhead in normal path
         x = x[0]                # indexing overhead in normal path
         # use single value
     else:
         x, y = x                # same overhead as with e.args less .args attribute lookup
         # use the unusual combo

Regards,
Bengt Richter



More information about the Python-list mailing list