Passing objects around an event queue in Python

python

Solution

Instead of passing in the function to call `func1` and the arguments that should be passed to the function, pass in a function `func2` that calls `func1` with the arguments that should be passed in.

d = {"a":1}
def p(val):
  print val

def func1():
  p(d["a"])

def call_it(func):
  func()

call_it(func1)
d["a"] = 111
call_it(func1)

Within `func1`, `d["a"]` is not evaluated until `func1` actually executes.

For your purposes, your queue would change to:

class EventQueue(object):
  def __init__(self):
    self.events = deque()
  def push(self, callable):
    self.events.append(callable)
  def process_next(self):
    self.events.popleft()()

`collections.deque` will be faster at popping from the front of the queue than a list.

And to use the `EventQueue`, you can use lambdas for quick anonymous function.

events2 = EventQueue()
foo1 = Foo(4)
bar1 = Bar(4, 2)

events2.push(lambda: foo1.update_value(1.5))
events2.push(lambda: bar1.print_alt_value(foo1.value))
events2.push(lambda: bar1.print_alt_value(foo1.return_bah()))

events2.process_next()
events2.process_next() # 36.0
events2.process_next() # 54.0

For Edit:

In this case you need to "capture" the value in a variable that is more tightly scoped than the loop. You can use a normal function and `partial()` to achieve this.

for name in names_list:
  def update(name):
    names_objs[name].update_value(2)
  events2.push(partial(update, name))

Problem

So i have a relatively convoluted setup for something I'm working on explained as follows: This is is python. and more of a rough outline, but it covers everything I need. Though the process next function is the same so feel free to clean that up if you want. ``` #timer event that runs every .1 second and processes events in a queue some_event_timer(): events.process_next() class Event_queue: def __init__(self): self.events = [] def push(self, event, parameters): self.events.insert(len(self.events), event, parameters) def process_next(self): event = self.pop(0) event[0](event[1]) class Foo: def __init__(self, start_value = 1): self.value = start_value def update_value(self, multiple): self.value *= multiple def return_bah(self) return self.value + 3 class Bar: def __init__(self, number1, number2): self.init = number1 self.add = number2 def print_alt_value(self, in_value): print in_value * (self.init + self.add) ``` That is a barebones of what I have, but it illustrates my problem: Doing the below ``` events2 = Event_queue2() foo1 = Foo(4) ----> foo1.value = 4 here bar1 = Bar(4, 2) events2.push(foo1.update_value,1.5) events2.push(bar1.print_alt_value,foo1.value) events2.push(bar.print_alt_value,foo1.return_bah()) events2.process_next() ----> should process update_value to change foo.value to 6 events2.process_next() ----> should process print_alt_value in bar class - expected 36 events2.process_next() ----> should process print_alt_value - expected 54 ``` I initially expected my output to be 36 6 * (4 + 2) I know why its not, foo1.value and foo1.return_bah() gets passed as an evaluated parameter (correct term?). What I really want is to pass the reference to the variable or the reference to the method, rather than having it evaluate when I put it in my event queue. Can anyone help me. I tried searching, but I couldn't piece together what I wanted exactly. TO get what I have now I initially looked at these threads: Calling a function of a module from a string with the function's name in Python Use a string to call function in Python But I don't see how to support parameters from that properly or how to support passing another function or reference to a variable from those. I suppose at least for the method call, I could perhaps pass the parameter as foo1.return.bah and evaluate in the process_next method, but I was hoping for a general way that would accept both standard variables and method calls, as the event_queue will take both. Thank you for the help Update edit: So I following the suggestion below, and got really close, but: Ok, so I followed your queue suggestion and got really close to what I want, but I don't completely understand the first part about multiple functions. I want to be able to call a dictionary of objects with this as well. for example: ``` names = ["test1", "test2"] for name in names: names_objs[name] = Foo(4) ``` Then when attempting to push via lambda ``` for name in names_list: events2.push(lambda: names_objs[name].update_value(2)) ``` doesn't work. When teh event actually gets processed it only runs on whatever name_objs[name] references, and if the name variable is no longer valid or has been modified outside the function, it is wrong. This actually wasn't surprising, but adding a: ``` name_obj_hold = name_objs[name] ``` then pushing that didn't either. it again only operates on whatever name_obj_hold last referenced. Can someone clarify the multiple funcs thing. I'm afraid I'm having trouble wrapping my head around it. basically I need the initial method call evaluated, so something like: names_objs[name].some_func(#something in here#) gets the proper method and associated with the right class object instance, but the #something in here# doesn't get evaluated (whether it is a variable or another function) until it actually gets called from the event queue.

Original source

Related problems