tags:

views:

604

answers:

5

how can I bind arguments to a python method to store a nullary functor for later invocation? similar to C++'s boost::bind

+12  A: 

functools.partial returns a callable based on a function with some or all of the arguments frozen.

~ $ python3.0
Python 3.0rc1 (r30rc1:66511, Sep 19 2008, 00:39:17) 
Type "help", "copyright", "credits" or "license" for more information.
>>> import functools
>>> print_hello = functools.partial(print, "hello, world")
>>> print_hello()
hello, world
>>> print_hello("how are you?")
hello, world how are you?
>>>

(I use Py3k in the example so that I can freeze the print function, since it seems like the simplest example. functools.partial has been available since 2.5.)

Jeremy Banks
+5  A: 

I'm not overly familiar with boost::bind, but the partial function from functools may be a good start:

>>> from functools import partial

>>> def f(a, b):
...     return a+b

>>> p = partial(f, 1, 2)
>>> p()
3

>>> p2 = partial(f, 1)
>>> p2(7)
8
Matthew Trevor
thanks. marked the top guy since he got it first.
Dustin Getz
A: 

Functors can be defined this way in Python. They're callable objects. The "binding" merely sets argument values.

class SomeFunctor( object ):
    def __init__( self, arg1, arg2=None ):
        self.arg1= arg1
        self.arg2= arg2
    def __call___( self, arg1=None, arg2=None ):
        a1= arg1 or self.arg1
        a2= arg2 or self.arg2
        # do something
        return

You can do things like

x= SomeFunctor( 3.456 )
x( arg2=123 )

y= SomeFunctor( 3.456, 123 )
y()
S.Lott
interesting pattern, lots of boilerplate for trivial functions though.
Dustin Getz
You can cut it down to something considerably simpler, depending on your actual use cases. The original question provides no guidance on how the binding occurs. Without specifics, there are too many bases to cover.
S.Lott
+4  A: 

If functools.partial is not available then it can be easily emulated:

>>> make_printer = lambda s: lambda: sys.stdout.write("%s\n" % s)
>>> import sys
>>> print_hello = make_printer("hello")
>>> print_hello()
hello

Or

def partial(func, *args, **kwargs):
    def f(*args_rest, **kwargs_rest):
        kw = kwargs.copy()
        kw.update(kwargs_rest)
        return func(*(args + args_rest), **kw) 
    return f

def f(a, b):
    return a + b

p = partial(f, 1, 2)
print p() # -> 3

p2 = partial(f, 1)
print p2(7) # -> 8

d = dict(a=2, b=3)
p3 = partial(f, **d)
print p3(), p3(a=3), p3() # -> 5 6 5
J.F. Sebastian
A: 

This would work, too:

def curry(func, *args):
    def curried(*innerargs):
       return func(*(args+innerargs))
    curried.__name__ = "%s(%s, ...)" % (func.__name__, ", ".join(map(str, args)))
    return curried

>>> w=curry(sys.stdout.write, "Hey there")
>>> w()
Hey there
Claudiu
why a down-vote here? It does work.
Claudiu