style query: function attributes for return codes?

george young gry at ll.mit.edu
Fri Dec 10 14:35:23 EST 2004


On Fri, 10 Dec 2004 16:40:25 GMT
Steven Bethard <steven.bethard at gmail.com> threw this fish to the penguins:

> george young wrote:
> > This is obviously just evil, since a misspelling in the string
> > return is treacherous.  I'm considering function attributes:
> > 
> > def get_connection():
> >     if tcp_conn():
> >         if server_allows_conn():
> >             return get_connection.GOOD
> >         else:
> >             return get_connection.BAD_AUTH
> >     else:
> >         return get_connection.NO_SERVER
> > get_connection.GOOD = 1
> > get_connection.BAD_AUTH = 2
> > get_connection.NO_SERVER = 3
> 
> Although in most cases this is probably okay, you're not guaranteed that 
> the name of your function will stay the same, so there are some hazards 
> in this style:
> 
>  >>> def f(x):
> ...     return f.y * x
> ...
>  >>> f.y = 100
>  >>> f(2)
> 200
>  >>> g, f = f, None
>  >>> g(2)
> Traceback (most recent call last):
>    File "<interactive input>", line 1, in ?
>    File "<interactive input>", line 2, in f
> AttributeError: 'NoneType' object has no attribute 'y'

Yes, I was worried about this.

> One option is to turn your function into a class:
> 
> class get_connection(object):
>      GOOD = 1
>      BAD_AUTH = 2
>      NO_SERVER = 3
>      def __new__(cls):
>          if tcp_conn():
>              if server_allows_conn():
>                  return cls.GOOD
>              else:
>                  return cls.BAD_AUTH
>          else:
>              return cls.NO_SERVER
> 
> This is a little sneaky here -- because you only need shared state 
> between all instances of get_connection, you don't actually ever need to 
> create an instance.  So I've overridden __new__ to return the result of 
> the function instead.  This allows you to call the function just like 
> you would have before.  I haven't tested the code above, but here's a 
> simpler example that works:
> 
>  >>> class look_ma_no_function(object):
> ...     X = 42
> ...     def __new__(cls):
> ...         return cls.X
> ...
>  >>> look_ma_no_function()
> 42

Hmm, this is quite clever, and indeed does what I want.  

I hesitate to adopt it, though, because it *looks* sneaky.
For readable and maintainable code, I think it may be a bit
too hackish... The original impetus for my post was to find
a clear, maintainable form.

I wonder about returning an object that tests True if all is
ok, and has boolean attributes to query if not True...:

def get_connection():
    class Ret:
        def __init__(self, badauth=False, noserver=False):
            self.badauth = badauth
            self.noserver = noserver
        def __nonzero__(self):
            return not(self.badauth and self.noserver)
    if tcp_conn():
        if server_allows_conn():
            return Ret()
        else:
            return Ret(badauth=True)
    else:
        return Ret(noserver=True)

ret = get_connection()
if not ret:
    if ret.badauth:
        ...


still seems a bit cumbersome in definition,
though the use is not bad...


-- George

-- 
"Are the gods not just?"  "Oh no, child.
What would become of us if they were?" (CSL)



More information about the Python-list mailing list