16

I'm revisiting some scheme excercises in python (if that makes sense) to find out what python can do in terms of FP. My problem concerns lambda in python : Can i define a general function in python with an operator as one of the arguments?

Think this :

def f (op,x,y):
    #return some lambda function that combines x and y in the appropriate way
    #i.e if op is +, then return x+y, if op is -, then return x-y etc

#Edit : added usage
#this should be called like this:
f(+, 1,2) #should return 3

I know this is possible in scheme, but is there something equivalent in python? I've gotten the impression that lambda in python is just a shorter way of defining a method, and I've not found any way to define a general combiner function in python.

1
  • It's worth noting that the biggest uses of lambdas have built-in functions: sum(), any(), all() Commented Nov 2, 2011 at 3:28

5 Answers 5

14

I can see some points in your question, lets go through them in order:

1. Can I pass a function as a parameter to someone?

Yes:

def f(op, x, y):
    return op(x, y)

def add(x, y):
    return x + y

f(add, 10, 7) #gives 17

2. What about operators then?

Unlike scheme, Python operators are not functions so you can't pass them directly as parameters. You can either create the wrapper functions yourself or you can import the operator module from the standard library.

import operator

operator.add(1, 2)
(lambda x,y : x+y)(1, 2)

Operators not being real functions is a little sad in most cases but at least Python gives us chained comparisons like 10 <= x < 100 in exchange...

3. So what is the difference between Python and Scheme then?

In the general sense, functions in Python are as powerful as functions in Scheme, however there are some things to note:

The lambda keyword is limited

You can only have a single expression as the function body

f = lambda x, y: x + y

Since there are a bunch of things in Python that are statements and not expressions (assignments, the 2.x print, ...), you often need to fall back to named functions instead.

There are closures

def make_printer(msg):
    def printer():
        print msg
    return printer

printer('a message')()

But mutating variables in them is a pain

This doesn't work. It tries to bind a new n for the inner function instead of using the outer one

def make_counter(n):
    def inc():
        n = n + 1
        return n
    return inc

new 3.x nonlocal keyword

def make_counter(n):
    def inc():
        nonlocal n
        n = n + 1
        return n
    return inc

workaround w/ mutable objects

def make_counter(n):
    nw = [n]
    def inc():
       nw[0] = nw[0] + 1
       return nw[0]
    return inc

Objects instead of closures. Uses the magic __call__ method to pretend its a function

class Counter:
    def __init__(self, n):
        self.n = n
    def __call__(self):
        self.n += 1
        return self.n
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, I understood how to do something scheme-equivalent (but not as elegant)
"You can only have a single expression as the function body" Well, technically in Scheme, everything is an expression (a set! call is an expression; and you can chain multiple "statements" together using begin, which also produces an expression). So it's not that different in that regard
@newacct: Yes, but many things that are expressions in scheme are not expressions in python. Python lambdas are more limited in what they can do.
8

Operators aren't really function in python, more like methods -- x + y is short for x.__add__(y), or y.__radd__(x). You can use the functions in the operator module to emulate the behavior you want.

1 Comment

Good answer. Consider adding an example f=lambda op,x,y: op(x,y); f(operator.add, 1, 2)
2

I think your best bet is to make a function that does the operator, and pass that:

def f(op, x, y):
    return op(x, y)

f(lambda x, y: x + y, 1, 2)

Looks a little redundant though when you can do:

f = lambda x, y: x + y

f(1, 2)

1 Comment

No. These functions already all exist in the operator module.
1

You cannot syntactically pass an operator in python. E.g. f(+) is a syntax error. However, if you consider op to be any function, you can use def or lambda:

def f(op, x, y):
  def op_func():
    return op(x, y)

  return op_func

or

def f(op, x, y):
  op_func = lambda: op(x, y)

  return op_func

In your case, you wish to evaluate the function:

def f(op, x, y):
    return op(x, y)

Remember that Python is interpreted, so even def statements are evaluated at runtime.

[ If for some reason you need to, you can access the built-in operators as functions using the operator module: http://docs.python.org/library/operator.html ]

Comments

0

Check operator module. All python operators are available there in the form of functions. example:

import operator    
operate = lambda op, x, y: op(x, y)
operate(operator.add, 1, 2)

1 Comment

Your answer is valid, but it doesn't answer my question. More precisely, my question is how and if I can define a general combiner-function in python :) I am looking to do something along the lines of folding (except I just want to do it for 2 variables instead of a data structure) : haskell.org/haskellwiki/Fold

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.