DRY functions with named attributes used as default arguments

Arnaud Delobelle arnodel at gmail.com
Sun Oct 9 09:19:34 EDT 2011


On 9 October 2011 13:20, Tim Chase <python.list at tim.thechases.com> wrote:
> My intent is to have a function object something like
>
>  def foo(arg1, arg2=foo.DEFAULT):
>    return int(do_stuff(arg1, arg2))
>  foo.SPECIAL = 42
>  foo.MONKEY = 31415
>  foo.DEFAULT = foo.SPECIAL
>
> so I can call it with either
>
>  result = foo(myarg)
>
> or
>
>  result = foo(myarg, foo.SPECIAL)
>
> However I can't do this because foo.DEFAULT isn't defined at the time the
> function is created.  I'd like to avoid hard-coding things while staying
> DRY, so I don't like
>
>  def foo(arg1, arg2=42)
>
> because the default might change due to business rule changes, I have a
> dangling "magic constant" and if the value of SPECIAL changes, I have to
> catch that it should be changed in two places.
>
> My current hack/abuse is to use __new__ in a class that can contain the
> information:
>
>  class foo(object):
>    SPECIAL = 42
>    MONKEY = 31415
>    DEFAULT = SPECIAL
>    def __new__(cls, arg1, arg2=DEFAULT):
>      return int(do_stuff(arg1, arg2))
>
>  i1 = foo("spatula")
>  i2 = foo("tapioca", foo.MONKEY)
>
> 1) is this "icky" (a term of art ;-)
> 2) or is this reasonable
> 3) or is there a better way to do what I want?
>

Why do you want these argument values to be attributes of the function?

Anyway, simpler than abusing classes:

foo_default = 42
def foo(arg1, arg2=foo_default):
    ...
foo.DEFAULT = foo_default
del foo_default
...

Or get the default at function runtime:

def foo(arg1, arg2=None):
    if arg2 is None:
        arg2 = foo.DEFAULT
    ...
foo.DEFAULT = 42
...

But I'd probably simply go for foo_DEFAULT, foo_MONKEY and
foo_SPECIAL.  They're also quicker (1 dict lookup instead of 2)

-- 
Arnaud



More information about the Python-list mailing list