1

In Python, is there anyway to pass a method to a higher order function, as you would if passing a regular function?

For example, let's say I have a string, "str", and depending on some condition, "cond", I want to apply some arbitrary method, "meth", to the string and return it. In code:

def func(str, meth, cond):
    ...
    if cond:
        str.meth()
    ...

Now, I know the above doesn't work. I also know that I could write something like:

def func(str, meth, cond):
    ...
    if cond:
        str = meth
    ...

and pass the object and method I want to execute to func like this: func(str, str.capitalize(), cond). The problem with the above is that:

  1. The above code doesn't make the intention of the function clear.
  2. If I, for example, want to modify "str" in anyway before the application of the method, then I end up with an incorrect result. Consider:

    def func(str, meth, cond):
        ...
        str += "a"
        ...
        if cond:
            str = meth
        ...
    

    will not work as intended.

So, returning to the beginning: is there anyway to accomplish what I want? Or am I approaching this from the wrong direction altogether?

upgrayedd
  • 129
  • 11
  • I think besides explaining what you are intending to implement it, you should also give more examples on how you wanna use this `func`? – satoru Jun 03 '15 at 02:45
  • What are you intending `str = meth` to do? I have a hunch you're looking for [`getattr`](https://docs.python.org/2/library/functions.html#getattr). – BrenBarn Jun 03 '15 at 02:48

4 Answers4

3

You can pass a method to a higher order function just like you would any function, you just have to pass it as object.method:

class Foo(object):
    def upper(self, s):
        return s.upper()

def func(s, method, cond):
    if cond:
        return method(s)
    else:
        return s

obj = Foo()
s = 'hello world'

print(func(s, obj.upper, 'hello' in s))   
print(func(s, obj.upper, 'goodbye' in s))

result:

HELLO WORLD
hello world

Or alternatively if you might try:

def func(s, method, cond):
    if cond:
        return method()
    else:
        return s

s = 'hello world'

print(func(s, s.upper, 'hello' in s))
print(func(s, s.upper, 'goodbye' in s))

However, as pointed out in the comments, this second approach won't work if you have a statement as s = s + 'a' inside the function, since you are just binding the local variable s to a new string, while method is still bound to the upper method of the string initially passed to the function.

Eric Appelt
  • 2,843
  • 15
  • 20
  • This is exactly what was looking to do. Thank you. – upgrayedd Jun 03 '15 at 03:07
  • Does the second alternative you suggest with the "s.upper" work in the scenario where the string is modified inside "func" before calling the method? – eugenioy Jun 03 '15 at 03:08
  • No, that is a really good point. Strings are immutable so if you perform `s = s + 'a'` you are just binding the local variable `s` to a new string, but `method` is still bound to `s.upper` of the old string without the extra 'a'. – Eric Appelt Jun 03 '15 at 03:27
1

I think what you what is to pass meth as an unbounded method, so it can be bounded to another object dynamicly.

>>> class C(object):
...     def foo(self):
...             print self
... 
>>> C.foo
<unbound method C.foo>
>>> C().foo
<bound method C.foo of <__main__.C object at 0xb708216c>>
>>> def func(obj, meth):
...     meth(obj)
... 
>>> c = C()
>>> func(c, C.foo)
<__main__.C object at 0xb70822ac>
>>> c
<__main__.C object at 0xb70822ac>

you can think an unbounded method as an regular who must take an object as its first argument

realli
  • 990
  • 6
  • 18
0

This does not allow you to call the function exactly as you wanted but it gets really close so perhaps it solves your problem.

def func(str, meth, cond):
    if cond:
        str = getattr(str, meth)()
    return str

print func("a", "capitalize", True)
print func("a", "capitalize", False)
eugenioy
  • 11,825
  • 28
  • 35
0

Don't quite sure what you're asking, but you could pass a function like the following.

def func(str, meth, cond):
    ...
    ...
    if cond:
        return meth(str)
    ...

And run it like this: (for example lowercase)

func("ABC", str.lower, True)

should return "abc"

Bruce Chou
  • 356
  • 2
  • 8