Skip to content

Instantly share code, notes, and snippets.

@Evgenus
Created July 25, 2011 16:12
Show Gist options
  • Save Evgenus/1104483 to your computer and use it in GitHub Desktop.
Save Evgenus/1104483 to your computer and use it in GitHub Desktop.
Actors?
from collections import deque
from functools import partial
from weakref import proxy
class Scheduler(object):
def __init__(self):
self.queue = deque()
def add(self, callable, *args, **kwargs):
print 'scheduling', callable, args, kwargs
self.queue.append(partial(callable, *args, **kwargs))
def tick(self):
if self.queue:
callable = self.queue.popleft()
callable()
return True
else:
return False
class Action(object):
scheduler = None
def __init__(self, preprocess=None):
self.preprocess = preprocess
self.callbacks = []
self.source = None
self.name = None
def __lshift__(self, callback):
if callback not in self.callbacks:
self.callbacks.append(callback)
return self
def __rshift__(self, callback):
if callback in self.callbacks:
self.callbacks.append(callback)
return self
def clear(self):
self.callbacks = []
def __repr__(self):
return "<Action {0} of {1}>".format(self.name, self.source)
def __call__(self, *args, **kwargs):
print 'invoking action', self
if self.preprocess is not None:
args, kwargs = self.preprocess(self.source, *args, **kwargs)
for callback in self.callbacks:
self.scheduler.add(callback, *args, **kwargs)
def clone(self):
new = self.__class__(self.preprocess)
new.name = self.name
return new
@classmethod
def wrap(cls, callable):
return cls(callable)
class Actor(object):
class __metaclass__(type):
def __new__(meta, name, bases, internals):
actions = internals['_actions'] = {}
for key, value in internals.iteritems():
if isinstance(value, Action):
actions[key] = value
cls = type.__new__(meta, name, bases, internals)
for key, action in actions.iteritems():
action.source = proxy(cls)
action.name = key
return cls
def __init__(self):
for name, cls_action in self._actions.iteritems():
action = cls_action.clone()
cls_action << action
action.source = proxy(self)
setattr(self, name, action)
class Receiver(Actor):
@Action.wrap
def input(self, value):
print '>>', self, value
return (value,), {}
class Sender(Actor):
output = Action()
def __init__(self, name, value):
super(Sender, self).__init__()
self.value = value
self.name = name
def do(self):
self.output(self.value)
def __repr__(self):
return "<Sender {0}>".format(self.name)
if __name__ == "__main__":
Action.scheduler = Scheduler()
sender1 = Sender('sender#1', 0)
sender2 = Sender('sender#2', 1)
receiver1 = Receiver()
receiver2 = Receiver()
sender1.output << receiver1.input
receiver1.input << receiver2.input << sender2.output
#sender2.output << receiver1.input << receiver2.input << sender1.output
sender1.do()
receiver1.input(10)
turn = 0
while True:
print '-' * 20, turn
if not Action.scheduler.tick():
break
turn += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment