lambda in python - python

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.

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

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.

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)

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 ]

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)

Related

Are functions and helper functions treated differently in python?

Over here, the main function is g(x) and the helper function is h(). I noticed I can get the output for g(3), simply by binding x=3 and then doing any of the three
print(g(x))
g(x)
z=g(x)
But on the other hand, I noticed h() is outputted only when I type "print(h())". Are my observations correct or did I make a mistake? And also what is the logic behind this weird discrimination?
I like to think of it this way. Usually, if you had a line like "5" or "x=5", python doesn't give an output of 5. But functions have been given a special feature where they are invoked in any of the 3 ways. It's only that this special feature is being 'withdrawn' in the case of helper functions
The code you have written is equivalent to this:
def g(x):
def h():
any_name_you_want = 'abc'
return any_name_you_want
x += 1
print("in g(x)", x)
print(h())
return x
You cannot assign to a non-local variable inside a function. When Python creates the namespace for h, x is local to h because the assignment requires python to add the namespace for x at runtime.
Hence your code is also equivalent to :
def g(x):
def h():
return 'abc'
x += 1
print("in g(x)", x)
print(h())
return x
To get a sense of what is happening, run the following and then read up on UnboundLocalError:
def g(x):
def h():
x = x
return x
x += 1
print("in g(x)", x)
print(h())
return x

Ways to define and use partially bound functions

The two ways I'm aware of to have a partially-bound function that can be later called is:
apply_twice = lambda f: lambda x: f(f(x))
square2x = apply_twice(lambda x: x*x)
square2x(2)
# 16
And
def apply_twice(f):
def apply(x):
return f(f(x))
return apply
square_2x=apply_twice(lambda x: x*x)
square_2x(4)
# 256
Are there any other common ways to pass around or use partially-bound functions?
functools.partial can be used to partially apply an ordinary Python function. This is especially useful if you already have a regular function and want to apply only some of the arguments.
from functools import partial
def apply_twice(f, x):
return f(f(x))
square2x = partial(apply_twice, lambda x: x*x)
print(square2x(4))
It's also important to remember that functions are only one type of callable in Python, and we're free to define callables ourselves as ordinary user-defined classes. So if you have some complex operation that you want to behave like a function, you can always write a class, which lets you document in more detail what it is and what the different parts mean.
class MyApplyTwice:
def __init__(self, f):
self.f = f
def __call__(self, x):
return self.f(self.f(x))
square2x = MyApplyTwice(lambda x: x*x)
print(square2x(4))
While overly verbose in this example, it can be helpful to write your function out as a class if it's going to be storing state long-term or might be doing confusing mutable things with its state. It's also useful to keep in mind for learning purposes, as it's a healthy reminder that closures and objects are two sides of the same coin. They're really the same thing, viewed in a different light.
You can also do this with functools.partial():
def apply_twice(f, x):
return f(f(x))
square_2x = functools.partial(apply_twice, lambda x: x*x)
This isn't really partial binding, assuming you mean partial application.
Partial application is when you create a function that does the same thing as another function by fixing some number of its arguments, producing a function of smaller arity (the arity of a function is the number of arugments it takes).
So, for example,
def foo(a, b, c):
return a + b + c
A partially applied version of foo would be something like:
def partial_foo(a, b):
return foo(a, b, 42)
Or, with a lambda expression:
partial_foo = lambda a, b: foo(a, b, 42)
However, note, the above goes against the official style guidelines, in PEP8, you shouldn't assign the result of lambda expressions to a name, if you are going to do that just use a full function defintion.
The module, functools, has a helper for partial application:
import functools
partial_foo = functools.partial(foo, c=42)
Note, you may have heard about "currying", which sometimes gets confused for partial application. Currying is when you decompose a n-arity function into N, 1-arity functions. So, more concretely, for foo:
curried_foo = lambda a: lambda b: lambda c: a + b + c
Or in long form:
def curried_foo(a):
def _curr0(b):
def _curr1(c):
return a + b + c
return _curr1
return _curr0
And the important part, curried_foo(1)(2)(3) == foo(1, 2, 3)

Higher Order Functions on Python

I am given a list of functions and asked to define plus(x,y) with add1 and repeated. plus is a function that takes in two numbers and returns the total. However, I cannot get any output with my definition. It just gives the name of the function. Any help is appreciated!
add1 = lambda x: x + 1
def compose(f, g):
return lambda x: f(g(x))
def repeated(f, n):
if n == 0:
return lambda x: x
else:
return compose(f, repeated(f, n - 1))
def plus(x, y):
return repeated(add1, y)
That is an interesting way to do addition. It works quite well, you just missed one thing. Repeated returns a function which will give the sum, not the sum itself. So you just have to call repeated(add1, y) on x like this
def plus(x, y):
return repeated(add1, y)(x)
The rest of the code works fine.
The detail is that plus returns a function and that's why you see the name of the function instead of a numeric value. I think that's why there is the x parameter in plus. Just change this line of code to
return repeated(add1, y)(x)
This will evaluate the return function of repeated with the value in x.
So using
plus(5, 1)
>> 6

From Haskell to Python: how to do currying?

I recently started coding in Python and I was wondering if it's possible to return a function that specializes another function.
For example, in Haskell you can create a function that adds 5 to any given number like this:
sumFive = (+5)
Is it somehow possible in Python?
I think the other answers are misunderstanding the question. I believe the OP is asking about partial application of a function, in his example the function is (+).
If the goal isn't partial application, the solution is as simple as:
def sumFive(x): return x + 5
For partial application in Python, we can use this function: https://docs.python.org/2/library/functools.html#functools.partial
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
Then, we must turn the + operator into a function (I don't believe there's a lightweight syntax to do so like in Haskell):
def plus(x, y): return x + y
Finally:
sumFive = partial(plus, 5)
Not nearly as nice as in Haskell, but it works:
>>> sumFive(7)
12
Python's design does not naturally support the evaluation of a multi-variable function into a sequence of single-variable functions (currying). As other answers point out, the related (but distinct) concept of partial application is more straightforward to do using partial from the functools module.
However, the PyMonad library supplies you with the tools to make currying possible in Python, providing a "collection of classes for programming with functors, applicative functors and monads."
Use the curry decorator to decorate a function that accepts any number of arguments:
from pymonad import curry
#curry
def add(x, y):
return x + y
It is then very easy to curry add. The syntax is not too dissimilar to Haskell's:
>>> add5 = add(5)
>>> add5(12)
17
Note that here the add and add5 functions are instances of PyMonad's Reader monad class, not a normal Python function object:
>>> add
<pymonad.Reader.Reader at 0x7f7024ccf908>
This allows, for example, the possibility of using simpler syntax to compose functions (easy to do in Haskell, normally much less so in Python).
Finally, it's worth noting that the infix operator + is not a Python function: + calls into the left-hand operand's __add__ method, or the right-hand operand's __radd__ method and returns the result. You'll need to decorate these class methods for the objects you're working with if you want to curry using + (disclaimer: I've not tried to do this yet).
Yup. Python supports lambda expressions:
sumFive = lambda x: x + 5
for i in range(5):
print sumFive(i),
#OUTPUT 5,6,7,8,9
Python functions can return functions, allowing you to create higher-order functions. For example, here is a higher-order function which can specialize a function of two variables:
def specialize(f,a,i):
def g(x):
if i == 0:
return f(a,x)
else:
return f(x,a)
return g
Used like this:
>>> def subtract(x,y): return x - y
>>> f = specialize(subtract,5,0)
>>> g = specialize(subtract,5,1)
>>> f(7)
-2
>>> g(7)
2
But -- there is really no need to reinvent the wheel, the module functools has a number of useful higher-order functions that any Haskell programmer would find useful, including partial for partial function application, which is what you are asking about.
As it was pointed out, python does have lambda functions, so the following does solve the problem:
# Haskell: sumFive = (+5)
sumFive = lambda x : x + 5
I think this is more useful with the fact that python has first class functions (1,2)
def summation(n, term):
total, k = 0, 1
while k <= n:
total, k = total + term(k), k + 1
return total
def identity(x):
return x
def sum_naturals(n):
return summation(n, identity)
sum_naturals(10) # Returns 55
# Now for something a bit more complex
def pi_term(x):
return 8 / ((4*x-3) * (4*x-1))
def pi_sum(n):
return summation(n, pi_term)
pi_sum(1e6) # returns: 3.141592153589902
You can find more on functional programming and python here
For the most generic Haskell style currying, look at partial from the functools module.

Creating Python function with partial parameters

I want to pass a Python function to another function with some of its parameters "filled out" ahead of time.
This is simplification what I am doing:
def add(x, y):
return x + y
def increment_factory(i): # create a function that increments by i
return (lambda y: add(i, y))
inc2 = increment_factory(2)
print inc2(3) # prints 5
I don't want to use some sort of passing of args and later exploding it with *args because the function I am passing inc2 into doesn't know to pass args to it.
This feels a bit too clever for a group project... is there a more straightforward or pythonic way to do this?
Thanks!
This is called currying, or partial application. You can use the built-in functools.partial(). Something like the following would do what you want.
import functools
def add(x,y):
return x + y
inc2 = functools.partial(add, 2)
print inc2(3)
You could also accomplish the same with a lambda function:
inc2 = lambda y: add(2, y)
print inc2(3)

Categories

Resources