On 10/09/11 10:37, Steven D'Aprano 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

What's the purpose of having both foo.SPECIAL and foo.DEFAULT?

As you later ask...

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,

If the business rule changes, you have to change foo.DEFAULT
anyway. So why  not cut out the middle man and change the
default argument in the function signature?

By indirecting through DEFAULT, I can change DEFAULT to point at another behavior-tweaking option in one place ("DEFAULT = SPECIAL") rather than in multiple places. However, I can't give a very good argument for just using

  def foo(arg1, arg2=SPECIAL)

and then, if it changes, just change *that* one location to

  def foo(arg1, arg2=MONKEY)

because, well, Python calls them default arguments for a reason :)

class Foo:
     SPECIAL = 42
     MONKEY = 31215
     DEFAULT = SPECIAL
     def __call__(self, arg1, arg2=DEFAULT):
         ...

foo = Foo()
del Foo

I did consider this (sorry I forgot to mention it) and it works well too. It's a little cleaner, as the magic happens in something named __call__ which is more obvious than overloading odd behavior into __new__. The instantiate-and-delete-the-class felt a little weird, and having both the class and the instance in the namespace felt weird. Granted the (ab)use of __new__ felt weird too, so neither wins by great margin. Which is part of my question: what's the least-worst way to do this? :)
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.

Then put it in one place.

SPECIAL = 42

def foo(arg1, arg2=SPECIAL):
     ...

and avoid the reference to foo.

I guess part of my attempt was to keep from littering the module namespace with things that only apply to the one function (and this also applies to C-like prefixes such as FOO_SPECIAL)

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

Seems okay to me. A little unusual, but only a little, not
"WTF is this code doing???" territory.

The code felt like it was riding the WTF-boundary, so I find your evaluation of "unusual but not WTF" encouraging.

Thanks for your thoughts,

-tkc




--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to