By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,621 Members | 1,104 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,621 IT Pros & Developers. It's quick & easy.

More decorator rumination

P: n/a
Over on comp.python.education we were discussing a (generally seen as)
misuse of decorators to build the definite integral of a function.
On thinking over the definite integral decorator, I had almost
decided that one necessary, but not sufficient, criterion for a
good decorator is that it must not change a function's arg list.
I was happy with this until just now.

I've been fighting wxPython a lot recently, and suddenly a good
working definition for a decorator came to me:

* A decorator mediates between a function and its environment.

In particular, I thought about something like:

@mousexy
def OnRightClick(self, x, y):
...

For those non-wx'ers, all GUI events come wrapped in an "event",
so all event-responding methods tend to look like:

def OnRightClick(self, event):
x = event.GetX()
y = event.GetY()

which looks like boilerplate to me. I'm wondering whether others
think this is an interesting insight into what decorators are "for,"
or they think I'm working on "the moral equivalent of a macro."

--Scott David Daniels
Sc***********@Acm.Org
Jul 18 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
On Wed, Mar 30, 2005 at 02:48:51PM -0800, Scott David Daniels wrote:
Over on comp.python.education we were discussing a (generally seen as)
misuse of decorators to build the definite integral of a function.
On thinking over the definite integral decorator, I had almost
decided that one necessary, but not sufficient, criterion for a
good decorator is that it must not change a function's arg list.
I was happy with this until just now.

I've been fighting wxPython a lot recently, and suddenly a good
working definition for a decorator came to me:

* A decorator mediates between a function and its environment.

In particular, I thought about something like:

@mousexy
def OnRightClick(self, x, y):
...

For those non-wx'ers, all GUI events come wrapped in an "event",
so all event-responding methods tend to look like:

def OnRightClick(self, event):
x = event.GetX()
y = event.GetY()

which looks like boilerplate to me. I'm wondering whether others
think this is an interesting insight into what decorators are "for,"
or they think I'm working on "the moral equivalent of a macro."


It might be plainer (and certainly more backwards compatible) to
wrap the function when setting the event handler.

EVT_BUTTON(self.frame, XRCID("ButtonName"), mousexy(self.OnRightClick))

As a matter of style & clairty, it just depends. If this is for
education I have no idea if putting the mutation in a decorator
might make it easier to explain to novices than explaining to them
that mousexy() creates a function that returns a function which is
bound to the event.

-jack

I haven't used wxPython, I just grabbed that example from
http://wiki.wxpython.org/index.cgi/XrcCheatSheet
Jul 18 '05 #2

P: n/a
Jack Diederich wrote:
On Wed, Mar 30, 2005 at 02:48:51PM -0800, Scott David Daniels wrote:
In particular, I thought about something like:

@mousexy
def OnRightClick(self, x, y):
...

so all event-responding methods tend to look like:

def OnRightClick(self, event):
x = event.GetX()
y = event.GetY()

It might be plainer (and certainly more backwards compatible) to
wrap the function when setting the event handler.

EVT_BUTTON(self.frame, XRCID("ButtonName"), mousexy(self.OnRightClick))

As a matter of style & clairty, it just depends.

I think this is probably the right approach.
If this is for education ...

I came here because it seemed to be drifting off-topic for education.

Thanks for the feedback.

-Scott David Daniels
Sc***********@Acm.Org
Jul 18 '05 #3

P: n/a
Scott David Daniels wrote:
In particular, I thought about something like:

@mousexy
def*OnRightClick(self,*x,*y):
...


You could somewhat generalize the idea -- have one argument in the wrapper
function provide the arguments missing in the wrapped one.

Here is a self-contained example, for the moment without support for keyword
arguments:

import inspect

class Event:
_x, _y, buttons = 1, 2, 3
def getX(self): return self._x
def getY(self): return self._y

_getter_for_name = dict(
x=Event.getX,
y=Event.getY,
buttons=lambda e: e.buttons
)

def event(fun):
getters = [_getter_for_name.get(arg) for arg in inspect.getargspec(fun
[0]]
def wrapped(*args):
# the Event instance must be the last argument
event = args[-1]
expanded = [get(event) for get in getters[len(args)-1:]]
args = args[:-1] + tuple(expanded)
return fun(*args)
return wrapped

class Alpha:
@event
def alpha(self, x):
print "--alpha--"
print "x =", x

@event
def beta(self, x, buttons):
print "--beta--"
print "x =", x
print "buttons =", buttons

@event
def gamma(buttons, y, x):
print "--gamma--"
print "x =", x
print "y =", y
print "buttons =", buttons

a = Alpha()
a.alpha(Event())
a.beta(Event())
gamma(Event())
# only the x argument will be set
# by the decorator (to Event().getX())
gamma("BUTTONS", "Y", Event())

Peter

Jul 18 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.