Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python reference to callback in dictionary

I have a class that specifies a set of callback functions (shown here as cb1 and cb2). I keep a map of these which I want to call after some event.

class Foo:
    cb1 = None
    cb2 = None

    def test(self, input):
        for (name, callback) in map:
            if name == input:
                if callback: callback()
                ...

    map = {'one':cb1, 'two':cb2}

def mycallback():
    print "mycallback()"

f = Foo()
f.cb1 = mycallback  # Register our callback
f.test('one')     # Nothing happens

Can you spot the problem?

What happens, is that when the class is initialized, the values of cb1 and cb2 (which are both None) are copied into the map. So even after a user 'registers' the callback (by assigning to cb1), the value in the map is still None and nothing gets called.

Since there's no such thing as 'by reference' in Python, how do I remedy this?

like image 467
Jonathon Reinhart Avatar asked Oct 12 '11 23:10

Jonathon Reinhart


2 Answers

Why not make your class explicitly handle registration?

import collections

class Foo(object):
    handlers = None

    def __init__(self):
        self.handlers = collections.defaultdict(set)

    def register(self, event, callback):
        self.handlers[event].add(callback)

    def fire(self, event, **kwargs):
        for handler in self.handlers.get(event, []):
            handler(**kwargs)

foo = Foo()
foo.register('one', mycallback)
foo.fire('one')
like image 58
patrys Avatar answered Sep 20 '22 01:09

patrys


Add a registration function. In Foo class:

def register(self, name, cb): self.map[name] = cb

and instead of:

f.cb1 = mycallback

use:

f.register('one', mycallback)  
like image 40
KQ. Avatar answered Sep 21 '22 01:09

KQ.