On Mon, 29 Dec 2008 21:13:55 -0500, R. Bernstein wrote: > How do I DRY the following code? > > class C(): [snip code]
Move the common stuff into methods (or possibly external functions). If you really need to, make them private by appending an underscore to the front of the name. class C(): def common1(self, *args): return "common1" def common2(self, *args): return "common2" def _more(self, *args): # Private, don't touch! return "more stuff" def f1(self, arg1, arg2=None, globals=None, locals=None): ... unique stuff #1 ... self.common1() ret = eval(args, globals, locals) self._more() return retval def f2(self, arg1, arg2=None, *args, **kwds): ... unique stuff #2 ... self.common1() ret = arg1(args, *args, **kwds) self.common2 return retval def f3(self, arg1, globals=None, locals=None): ... unique stuff #3 ... self.common1() exec cmd in globals, locals self.common2() return None # unneeded def f4(self, arg1, globals=None, locals=None): ... unique stuff #4 ... self.common1() execfile(args, globals, locals) self._more() An explicit "return None" is probably not needed. Python functions and methods automatically return None if they reach the end of the function. > Above there are two kinds of duplication: that within class C and that > outside which creates an instance of the class C and calls the > corresponding method. Do you really need them? If so, you're repeating yourself by definition. That's not necessarily a problem, the stand-alone functions are just wrappers of methods. You can decrease (but not eliminate) the amount of repeated code with a factory function: def build_standalone(methodname, docstring=None): def function(arg, arg2=None, globals=None, locals=None): c = C() return c.getattr(methodname)(arg, arg2, globals, locals) function.__name__ = methodname function.__doc__ = docstring return function f1 = build_standalone('f1', "Docstring f1") f2 = build_standalone('f2', "Docstring f2") f3 = build_standalone('f3', "Docstring f3") There's no way to avoid the repeated f1 etc. But honestly, with only three such functions, I'd consider that overkill. > Lest the above be too abstract, those who want to look at the full > (and redundant) code: > > http://code.google.com/p/pydbg/source/browse/trunk/api/pydbg/api/ debugger.py You have parameters called Globals and Locals. It's the usual Python convention that names starting with a leading uppercase letter is a class. To avoid shadowing the built-ins, it would be more conventional to write them as globals_ and locals_. You may or may not care about following the convention :) I notice you have code like the following: if Globals is None: import __main__ Globals = __main__.__dict__ I would have written that like: if Globals is None: Globals = globals() or even if Globals is None: from __main__ import __dict__ as Globals You also have at least one unnecessary pass statement: if not isinstance(expr, types.CodeType): expr = expr+'\n' pass The pass isn't needed. In your runcall() method, you say: res = None self.start(start_opts) try: res = func(*args, **kwds) except DebuggerQuit: pass finally: self.stop() return res This is probably better written as: self.start(start_opts) try: return func(*args, **kwds) except DebuggerQuit: return None finally: self.stop() -- Steven -- http://mail.python.org/mailman/listinfo/python-list