How do I DRY the following code?

Patrick Mullen saluk64007 at gmail.com
Tue Dec 30 00:57:22 EST 2008


On Mon, Dec 29, 2008 at 6:13 PM, R. Bernstein <rocky at panix.com> wrote:
> How do I DRY the following code?
>
> class C():
>
>  def f1(self, arg1, arg2=None, globals=None, locals=None):
>      ... unique stuff #1 ...
>      ... some common stuff #1 ...
>      ret = eval(args, globals, locals)
>      ... more stuff #2 ...
>      return retval

Possibly make a separate method with the common stuff.  Make each
variant function call various other methods with the "different stuff"
being different arguments to shared functions, or calling slightly
different methods.  Take the code one issue at a time, this seems
complex enough that there is no easy, quick refactoring that can be
done.

Something like this is what I see, but it's hazy:

def f1(self,args):
   ... unique stuff #1
   self.commonstuff1()
   ret = self.myeval(args)
   self.commonstuff2()
   return retval

Looking at the actual code, my thoughts are that you pick the most
common base "run" type and stick with that, making other run types
modify that.  For instance, you could pass an evaluator function in to
the base run() method, and call that, instead of having a separate
case for exec or eval.  runfunc would pass in the function itself as
the evaluator.  So it looks more like this:

def run(blah, blah, BLAH, BLAAAAAH, evaluator, locals, globals):
   do much stuff
   evaluator(code,locals,globals)
   do much other stuff
def runfunc(blah, func):
   run(blah, value_defined_for_runfunc, func, locals, globals)
def runeval(blah):
   run(blah, value_defined_for_runfunc, eval, locals globals)

The thing I don't like about this is it could very well make the main
run function even hairier than it already is.  But I don't think it
has to be that way.

This may not be the ideal solution either, if you can get a nice set
of lower-level methods which each run method compose in different ways
to produce the final result.

> f1(...):
>  "Docstring f1"
>  c = C()
>  return c.f1(...)
>
> f2(...):
>  "Docstring f2"
>  c = C()
>  return c.f2(...)

Why not just do either this:
C().f2(..) where you need f2

Or make the function an argument:
f(name):
  c = C()
  return getattr(c,name)()

I'm not sure why you need the top-level functions though.  If you
really need them, and don't want to add an extra argument, I don't
think there is a simpler way to do than you have.



More information about the Python-list mailing list