I am working on some legacy code (created by someone in love with spaghetti code) that has over 150 getters and over 150 setters. The getters look like this:
def GetLoadFee(self):
r_str = ""
if len(self._LoadFee) > 20:
r_str = self._LoadFee[:20]
else:
r_str = self._LoadFee.strip()
return r_str.strip()
def GetCurrency(self):
r_str = ""
if len(self._Currency) > 3:
r_str = self._Currency[:3]
else:
r_str = self._Currency.strip()
return r_str.strip()
I would love to take the contents of each of these Getters and put them into a decorator /closure or some other method to make this code easier to maintain. The Setters are all one liners, so they’re not as important. But they are basically all the same too. Any ideas to make this less painful?
NOTE: I still need the original Getter names as they are used in other programs as this nasty script is used in lots of other legacy code.
Now, you can do this:
Then:
Clearly, there’s also a lot of repetitive and unnecessary stuff in the original function. (And it would be much better to use PEP8-style names for your properties.) But obviously it’s much easier to refactor first, then improve, than the other way around. (In other words, start here, but don’t stop here.)
From the comments:
The method maker doesn’t actually get the
selfreference. There is noselfreference to get at the time the method maker is being called. But there also is noselfreference to get for a normal method at the time the class is being defined. In either case, you’re just defining a function that takesselfas its first parameter, and it somehow magically gets the appropriateselfwhen you call it.To really understand how this actually works, you need to know about descriptors. See Implementing Descriptors and Invoking Descriptors (or the 3.3 version), read it over a few times, look at how the
@propertydecorator is implemented, play around in the interactive interpreter, give up, go to sleep, and try again tomorrow, and it should all click. But it’s easier if you learn the magic version first, so let’s do that, using a simpler example:An unbound method is just a thing with an
im_classholding its class, anim_funcholding a normal function, and anim_selfholdingNone. And when you dofake1 = funcin the class definition, orC.fake2 = funcafter the fact, you don’t actually end up withfuncitself as the value offake1orfake2, but with an unbound method wrapped aroundfunc, itsim_classpointing atC.When you take an instance of a class, all of its unbound methods become bound methods. If you look at the bound methods’ attributes, they’re the same as the unbound methods, except that
im_selfiscinstead ofNone. And when you callc.fake1(), that’s how it works—Python sees thatc.fake1is a bound method, so, in effect, it callsc.fake1.im_func(c.fake1.im_self). And that’s howfakegets its self parameter.(This all becomes simpler in Python 3, because there’s no such thing as unbound methods anymore, but I assume you care more about Python 2 given that you’re dealing with a huge mess of legacy code.)