1

I have class Window. This class has method onClick which gets argument the id of control clicked on that window (i can not change the way it's work):

 class Window(SoneBaseWindowClass):

    def onClick(self,controlID):
        print controlID

I want to make decorator which will add my method to callback stack. And than method onClick will call certain method when certain control get clicked. So:

class Window(SoneBaseWindowClass):
    def __init__(self):
        callback_stack = {}

    def onClick(self,controlId):
        callback = self.callback_stack.get(controlID)
        if callback is not None:
            callback()

    # suppose to add decorated method to a callback_stack
    def onclick_decorator(method):
        pass

So I need to make decorator which will add some method to callback_stack. Example using.

class MyWindow(Window):

    @onclick_decorator(12345)
    def someMethod(self):
        print "Gets called when control with id 12345 clicked"

Actually the question is how can i get acces to class from onclick_decorator Self is not passed to that method. So i can assume that it could get acces to class, but could not figure out how.

Pol
  • 24,517
  • 28
  • 74
  • 95

1 Answers1

2

The way to deal with this kind of situation is to have the decorator to add the decorated methods to a data structure (CallbackStack in your case) - but to attach that data structure to the class, you need some action when the class is created (i.e. parsed) - since while it is being parsed, the decorator, as you say, don't have access to either the instance or class.

In modern Python (even Python 2) there are two ways to do that: you eitehr use a metclass, or a class decorator. But I don think class decorators are available for Python 2.4 - so you will need to have a metaclass.

It is not that complicated - the __new__method on the metaclass gets passd the dictionary that was constructed during parsing. All your decorator has to do is to mark the desired methods with an attribute that the metaclass can find - and build your callback_stack from these markings. The call_back stack can even be a dictionary:

def on_click_decorator(key):
    def real_decorator(func):
        setattr(func, "_callback_to", key)
        return func
    return real_decorator


class Meta(type):
    def __new__(metacls, name, bases, dct):
        callback_stack = {}
        for name, value in dct.items():
            if hasattr(value, "_callback_to"):
                callback_stack[value._callback_to] = key
        dct["callback_stack"] = callback_stack
        # we've done all needed manipulation - no
        # need for the class to be from a special type - so we
        # don't call type.__new__
        return type(name, bases, dct)

Now you can, from inside your methods, call self.callback_stack[controlID] to retrieve the registered functions (ou get them as functions not methods with the code above, so pass "self" explicitly to them).

jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • I tried to make it with class. I was surprised but class decorator works in my python2.4 (the one that is build in xbmc) – Pol Apr 13 '12 at 16:53
  • But you way is more advanced. i'll try to make through metaclass as you pointed me. Thank you very match. Will be good start for me to understand metaclasses. – Pol Apr 13 '12 at 16:57