How to pass arguments to a python greenlet as additional arguments

1.7k views Asked by At

I'm looking for a way to pass function arguments through another function, in a manner identical to Stackless' tasklet instantiation:

stackless.tasklet(function_being_called)(*args)

So far the best way I've come up with is:

mylib.tasklet(function_being_called,*args)

which works, but is not identical to Stackless' syntax. I'm not sure where to look in the documentation to find out how to accomplish this (hence the rather ambiguous title for this question). Is this even possible, or is it part of Stackless' changes to the interpreter?

EDIT: I'm now aware that there is an approach which will work for functions, but I'm unsure if it will work in my case. I'm using the greenlet library: greenlet threads obtain args when the greenlet is switch()ed to, not on instantiation. Calling them as shown below results in

TypeError: 'greenlet.greenlet' object is not callable.

Using greenlet.greenlet(function(args)) (still not right syntax) executes immediately and still requires args in the switch() method. Hence I currently store variables in-class, using the syntax shown above, to pass when calling switch(). Hope this doesn't change the question too much!

As requested, here is the code in question. First, a variant on eri's answer (DISCLAIMER: I've never used decorators before):

import greenlet # Background "greenlet" threadlet library

_scheduled = [] # Scheduler queue

def newtasklet(func): # Returns a greenlet-making function & switch() arguments. 
    def inner(*args,**kwargs):
        newgreenlet = greenlet.greenlet(func,None)
        return newgreenlet,args,kwargs
    return inner

class tasklet():
    def __init__(self,function=None):
        global _scheduled 
        initializer = newtasklet(function)
        self.greenlet,self.variables,self.kvars = initializer()
        _scheduled.append(self)
        self.blocked = False

tasklet(print)("A simple test using the print function.")

Traceback (most recent call last):
  File "<pyshell#604>", line 1, in <module>
    tasklet(print)("A simple test using the print function.")
TypeError: 'tasklet' object is not callable

Original code (working but not syntactically ideal):

class tasklet(): 
    def __init__(self,function=None,*variables,parent=None):
        global _scheduled
        self.greenlet = greenlet.greenlet(function,parent)
        self.variables = variables
        _scheduled.append(self)
        self.blocked = False

>>> tasklet(print,"A simple test using the print function.")
<__main__.tasklet object at 0x7f352280e610>
>>> a = _scheduled.pop()
>>> a.greenlet.switch(*a.variables)
A simple test using the print function.
5

There are 5 answers

3
mr2ert On

I've never used stackless before, but stackless.tasklet(function_being_called) is returning a function object that is being given the parameters (*args). If you want the syntax to be the same for your tasklet, then mylib.tasklet should return a function.

For example:

def inner(*args):
    print '|'.join(args)

def foo(func):
    return func

foo(inner)('hello', 'world')

Outputs:

hello|world
0
Gabe On

I'm not familiar with Stackless, but what's happening there is that the tasklet functions returns a reference to the function, that is then called by the interpreter with the *args.

An example:

def return_the_method(method):
    return method

def add_two(num1, num2):
    return num1 + num2

If you have this, then run return_the_method(add_two)(1, 2), you'll get 3.

3
eri On

stackless.tasklet is decorator. Rewrite your function as decorator.

def tasklet(f):
  def inner(*args,**kwargs):
    t= Thread(target=f,args=args,kwargs=kwargs)
    t.start()
    return t
  return inner


task=tasklet(your_func)(arg)
task.join()

It runs your_func in separate thread and returns thread instance.

0
user2479509 On

Just make sure to return a function from mylib.tasklet:

>>> def call_me(func):
        # do something here, like spawn a thread
        return func

>>> def being_called(str1, str2, str3):
        print str1
        print str2
        print str3

>>> call_me(being_called)('a', 'b', 'c')
a
b
c
0
Aderbal On

import greenlet # Background "greenlet" threadlet library

_scheduled = [] # Scheduler queue

def newtasklet(func): # Returns a greenlet-making function & switch() arguments. def inner(*args,**kwargs): newgreenlet = greenlet.greenlet(func,None) return newgreenlet,args,kwargs return inner

class tasklet(): def init(self,function=None): global _scheduled initializer = newtasklet(function) self.greenlet,self.variables,self.kvars = initializer() _scheduled.append(self) self.blocked = False def call(self, function=None): return function

def imprime(a): print a

tasklet(imprime)("A simple test using the print function.")