def make_generic_getter(name, maxlen):
def getter(self):
value = getattr(self, name)
r_str = ""
if len(value) > maxlen:
r_str = value[:maxlen]
else:
r_str = value.strip()
return r_str.strip()
return getter
Now, you can do this:
class Foo(object):
def __init__(self):
self._Bar = 'abc'
self._Baz = 'def'
GetBar = make_generic_getter('_Bar', 5)
GetBaz = make_generic_getter('_Baz', 2)
Then:
>>> f = Foo()
>>> f.GetBar()
'abc'
>>> f.GetBaz()
'de'
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:
How does the method maker get the "self" reference?
The method maker doesn't actually get the self
reference. There is no self
reference to get at the time the method maker is being called. But there also is no self
reference to get for a normal method at the time the class is being defined. In either case, you're just defining a function that takes self
as its first parameter, and it somehow magically gets the appropriate self
when 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 @property
decorator 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:
>>> def func(self): pass
>>> class C(object):
... def meth(self): pass
... fake1 = func
>>> C.fake2 = func
>>> func, C.meth, C.fake1, C.fake2
(<function __main__.func>, <unbound method C.meth>, <unbound method C.func>, <unbound method C.func>)
An unbound method is just a thing with an im_class
holding its class, an im_func
holding a normal function, and an im_self
holding None
. And when you do fake1 = func
in the class definition, or C.fake2 = func
after the fact, you don't actually end up with func
itself as the value of fake1
or fake2
, but with an unbound method wrapped around func
, its im_class
pointing at C
.
>>> c = C()
>>> c.meth, c.fake1
(<bound method C.meth of <__main__.C object at 0x111ebb0d0>>, <bound method C.meth of <__main__.C object at 0x111ebb0d0>>)
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_self
is c
instead of None
. And when you call c.fake1()
, that's how it works—Python sees that c.fake1
is a bound method, so, in effect, it calls c.fake1.im_func(c.fake1.im_self)
. And that's how fake
gets 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.)