views:

143

answers:

2

I'm using a Python API that expects me to pass it a function. However, for various reasons, I want to pass it a method, because I want the function to behave different depending on the instance it belongs to. If I pass it a method, the API will not call it with the correct 'self' argument, so I'm wondering how to turn a method into a function that knows what 'self' it belongs to.

There are a couple of ways that I can think of to do this, including using a lambda and a closure. I've included some examples of this below, but I'm wondering if there is a standard mechanism for achieving the same effect.

class A(object):
    def hello(self, salutation):
        print('%s, my name is %s' % (salutation, str(self)))

    def bind_hello1(self):
        return lambda x: self.hello(x)

    def bind_hello2(self):
        def hello2(*args):
            self.hello(*args)
        return hello2


>>> a1, a2 = A(), A()
>>> a1.hello('Greetings'); a2.hello('Greetings')
Greetings, my name is <__main__.A object at 0x71570>
Greetings, my name is <__main__.A object at 0x71590>

>>> f1, f2 = a1.bind_hello1(), a2.bind_hello1()
>>> f1('Salutations'); f2('Salutations')
Salutations, my name is <__main__.A object at 0x71570>
Salutations, my name is <__main__.A object at 0x71590>

>>> f1, f2 = a1.bind_hello2(), a2.bind_hello2()
>>> f1('Aloha'); f2('Aloha')
Aloha, my name is <__main__.A object at 0x71570>
Aloha, my name is <__main__.A object at 0x71590>
+6  A: 

Will passing in the method bound to a instance work? If so, you don't have to do anything special.

In [2]: class C(object):
   ...:     def method(self, a, b, c):
   ...:         print a, b, c
   ...:
   ...:

In [3]: def api_function(a_func):
   ...:     a_func("One Fish", "Two Fish", "Blue Fish")
   ...:
   ...:

In [4]: c = C()

In [5]: api_function(c.method)
One Fish Two Fish Blue Fish
Ryan
Um... I'm an idiot. That works.
Nick
A: 

You may want to clarify your question. As Ryan points out,

def callback(fn):
    fn('Welcome')
callback(a1.hello)
callback(a2.hello)

will result in hello being called with the correct self bound, a1 or a2. If you are not experiencing this, something is deeply wrong, because that's how Python works.

What you seem to want, judging by what you've written, is to bind arguments -- in other words, currying. You can find examples all over the place, but Recipe 52549 has the best Pythonic appearance, by my tastes.

class curry:
    def __init__(self, fun, *args, **kwargs):
        self.fun = fun
        self.pending = args[:]
        self.kwargs = kwargs.copy()

    def __call__(self, *args, **kwargs):
        if kwargs and self.kwargs:
            kw = self.kwargs.copy()
            kw.update(kwargs)
        else:
            kw = kwargs or self.kwargs

        return self.fun(*(self.pending + args), **kw)

f1 = curry(a1.hello, 'Salutations')
f1()  #  == a1.hello('Salutations')
ephemient
What you show isn't currying - it's partial application.
Evan Fosmark
Wikipedia calls them the same thing. http://en.wikipedia.org/wiki/Currying"The practical motivation for currying is that very often the functions obtained by supplying some but not all of the arguments to a curried function (often called partial application)"
recursive