macro FAQ
Hannu Kankaanpää
hanzspam at yahoo.com.au
Tue Aug 26 10:42:10 EDT 2003
Jacek Generowicz <jacek.generowicz at cern.ch> wrote in message news:<tyf1xv8ao8q.fsf at pcepsft001.cern.ch>...
> hanzspam at yahoo.com.au (Hannu Kankaanpää) writes:
> > Obviously this was quite unsatisfactory. I ended up
> > putting the axis code in a separate class
>
> Do you mean "function" rather than "class" ?
Actually, I did mean class. Normally I'd have
class Widget:
def __init__(self):
self.x = 0
self.y = 0
self.width = 0
self.height = 0
def getWidth(self):
return self.width # normally they wouldn't be this empty!
def getHeight(self):
return self.height
But by wrapping it inside a new class, I could get rid of
the duplication (partly, at least):
class Widget:
def __init__(self):
self.x = Widget.Axis(0, 0)
self.y = Widget.Axis(0, 0)
class Axis:
def __init__(self, pos, size)
self.pos = pos
self.size = size
def getSize(self): # this is only once here now
return self.size
While this tiny example doesn't show decrease in code
size, it shows that I have a common definition for all
"Axis"-specific code inside the appropriate Axis class.
Rest of the Widget methods would be in the widget class.
Thus self.x.getSize() instead of self.getWidth().
> > so I could
> > use them interchangeably. I.e. If I passed
> > func(self.y, self.x)
> > and then
> > func(self.x, self.y)
> >
> > I would get the same effect on both axises. But this
> > would've been an excellent place for macros IMO
>
> I don't see what you gain by using a macro, wrt to using a function in
> _this_ case.
Ok, it was a bad example. I hope the code above shows
a bit more clearly what I wanted. Anyway, without the code
in the axis-class, I would've had to often say
self.x = func(self.x, self.y, self.width, self.height)
self.y = func(self.y, self.x, self.height, self.width)
Instead of
func(self.x, self.y)
func(self.y, self.x)
Which could modify the axis-specific stuff within the
func()tion. (self.x is no longer a non-modifiable number,
but a modifiable class)
> So you would not only replace whole symbols, but even fragments of
> symbols (getSize -> getHeight), and thus macically/implicitly create
> new symbols. Many people consider this bad practice.
Well, I don't, really. Like any macro that could do something
weird, it just needs to be properly understood by anyone who
wishes to read the code.
> Incidentally, in this case, having a string based code representation
> would make your job much easier than the structured representation
> which Lisp uses. In a string you'd merely do a search and replace; in
> an s-expression you would have to recursively search for all symbols
> in all sub-expressions, and then do the search and replace within the
> name of each symbol you find.
Well, such a recursive search isn't a problem - With help from
a macro ;)
> > This way, I could've got no duplicated code but
> > also a more intuitive interface than I currently have
> > (to get width, one needs to type obj.x.getSize() instead
> > of obj.getWidth()). And it's obvious this kind of "defBoth"
> > wouldn't be added as a language level construct -- Thus
> > macros are the only good solution.
>
> Cue metaclass solution ... :-)
How could metaclasses help? I'm quite inexperienced with them.
Anyway, if I take the eval route, I might as well do
defBoth('''getSize():
return size''')
,retreive appropriate locals() from the stack and modify it
to include the new functions. I'd rather not, though :-)
More information about the Python-list
mailing list