Return Function description as string? - python

Is it possible to output the content of a user-defined function as a string (not the enumeration, but just the function call):
Function:
def sum(x,y):
return x+y
Function content as a string:
"sum(), return x+y"
The inspect function might have worked but it seems to be for just python 2.5 and below?

The inspect module works just fine for retrieving source code, this is not limited to older Python versions.
Provided the source is available (e.g. the function is not defined in C code or the interactive interpreter, or was imported from a module for which only the .pyc bytecode cache is available), then you can use:
import inspect
import re
import textwrap
def function_description(f):
# remove the `def` statement.
source = inspect.getsource(f).partition(':')[-1]
first, _, rest = source.partition('\n')
if not first.strip(): # only whitespace left, so not a one-liner
source = rest
return "{}(), {}".format(
f.__name__,
textwrap.dedent(source))
Demo:
>>> print open('demo.py').read() # show source code
def sum(x, y):
return x + y
def mean(x, y): return sum(x, y) / 2
def factorial(x):
product = 1
for i in xrange(1, x + 1):
product *= i
return product
>>> from demo import sum, mean, factorial
>>> print function_description(sum)
sum(), return x + y
>>> print function_description(mean)
mean(), return sum(x, y) / 2
>>> print function_description(factorial)
factorial(), product = 1
for i in xrange(1, x + 1):
product *= i
return product

Related

Create composite function from arbitrary number of functions [duplicate]

This question already has an answer here:
Compute a chain of functions in python
(1 answer)
Closed 7 months ago.
I am reading Joseph Howse OpenCV book. In the appendix, he's discussing creation of composite function from 2 other functions, as follows:
def createCompositeFunction(func1, func2):
return lambda x : func2(func1(x))
How could I write this for an arbitrary number of functions, like so
def createCompositeFunction(*funcs):
pass
I assume this should be done using recursion, but I can not wrap my head around it.
Any suggestions?
You don't need recursion; this is a simple iterative problem:
def createCompositeFunction(*funcs):
def apply(x):
for func in funcs:
x = func(x)
return x
return apply
def f1(x):
return x + 2
def f2(x):
return x * 3
def f3(x):
return x / 2
comp = createCompositeFunction(f1, f2, f3)
print("comp(1) =", comp(1))
print("comp(2) =", comp(2))
Running the above code will output:
comp(1) = 4.5
comp(2) = 6.0
What you're asking for in functional programming terms is a reducer higher-order function. Python provides functools.reduce to this end:
def reduce(function, iterable, initializer=None):
Where function should be an applicator, iterable is the chain of funcs you want to apply, and initializer is your argument.
Here's a simple example on one argument:
from functools import reduce
def sub1(a):
return a - 1
def mul2(a):
return a * 2
def apply(x, f):
return f(x)
def compose(*fns):
return lambda x: reduce(apply, fns, x)
print(compose(sub1, mul2)(4)) # => 6
You can partial or lambda in extra args as needed:
from functools import partial, reduce
from operator import mul, sub
def compose(*fns):
return lambda x: reduce(lambda x, f: f(x), fns, x)
print(compose(lambda x: sub(x, 2), partial(mul, 3))(4)) # => 6
There are a lot of ways to go with this sort of thing, so I'll leave it at this absent further information about your use case.
As it turns out, this is pretty much a more fleshed-out version of Compute a chain of functions in python.
#ggorlen offers an efficient solution using reduce. Here's a recursive form -
# right-to-left composition
def compose(f = lambda x: x, *funcs):
if not funcs:
return f
else:
return lambda x: f(compose(*funcs)(x))
# left-to-right composition
def compose(f = lambda x: x, *funcs):
if not funcs:
return f
else:
return lambda x: compose(*funcs)(f(x))
Using separate definitions for identity and comp2 may make it easier to see how things are working -
def identity(x):
return x
def comp2(f, g):
return lambda x: f(g(x))
# right-to-left composition
def compose(f = identity, *funcs):
if not funcs:
return f
else:
return comp2(f, compose(*funcs))
# left-to-right composition
def compose(f = identity, *funcs):
if not funcs:
return f
else:
return comp2(compose(*funcs), f)
Here's a complete demo using left-to-right compose and a curry helper. Because curry accepts function as input, we can conveniently use it as a decorator too -
def curry(arity):
def loop(f, n, args):
return f(*args) if n == 0 else lambda x: loop(f, n - 1, (*args, x))
return lambda f: loop(f, arity, ())
#curry(2)
def add(x, y):
return x + y
#curry(2)
def mul(x, y):
return x * y;
myfunc = compose(add(1), mul(2), mul(2), mul(2))
print(myfunc(0))
# (((0 + 1) * 2) * 2) * 2
# 8
You can use accumulate from functools (and keep intermediate results):
from itertools import accumulate
def f1(x): return x + 2
def f2(x): return x * 3
def f3(x): return x / 4
def createCompositeFunction(func1, func2):
return lambda x: func2(func1(x))
# For x=3
l = [f(3) for f in accumulate([f1, f2, f3], createCompositeFunction)]
Output:
>>> l
[5, 15, 3.75] # <- the last item l[-1] is the final value
#larsks has a pretty nice answer. If you're interested in recursion specifically, here's an option:
def createCompositeFunction(*funcs):
func = funcs[0]
funcs = funcs[1:]
if len(funcs) == 0:
return func
return lambda x: func(createCompositeFunction(*funcs)(x))
def square(x):
return x ** 2
square_thrice = createCompositeFunction(square, square, square)
print(square_thrice(2))
Output:
>>> 256
Recursive approached: Assumed that the range of each function is the same of the domain of the next one.
The freedom in the initial value infers a condition on the outputs of the function, it cannot be None (filter as is not None to avoid automatic casting, i.e. 1<-->True, ''<-->False, ...).
def direct_composition(funcs, init_value=None):
if funcs:
if init_value is not None:
return direct_composition(funcs[1:], funcs[0](init_value))
return direct_composition(funcs[1:], funcs[0]())
return init_value
# sample functions
def a0(): return 'a' # initial function with no args
def a(x): return 'a'+x
def b(x): return 'b' + x
def c(x): return 'c' + x
# test with initial function taking parameters
funcs = a, b, c
direct_composition(funcs, '>')
#cba>
# test with initial function taking no parameters
funcs = a0, a, b, c
direct_composition(funcs)
#cba
Double layer approach with no side-effects, no restriction on the output of the functions. A pushward is when you fix a function that will be the most internal one and the other functions will be applied in increasing order to it.
def pushforward(f, initial_value=None):
def apply(value, funcs):
if funcs:
return apply(funcs[0](value), funcs[1:])
return value
return (lambda funcs: apply(f(initial_value), funcs)) if initial_value else (lambda funcs: apply(f(), funcs))
# with no initial value
f_init = a0
funcs = a, b, c
res = pushforward(f_init)(funcs)
print(res)
# with initial value
f_init = a
funcs = b, c
res = pushforward(f_init, '>')(funcs)
print(res)

Module functions with default arguments and namespaces?

I want to collect a few generally useful function into a module my_module. These functions must have default arguments that are variables in the workspace. When I move these functions out from the main code to the module, and then import them into the main code, then I get an error since these default arguments cannot be found.
y = 1;
def f(x, y=y):
sum = x+y
return sum
f(1)
And when f instead is imported from my_module we have
y = 1
from my_module import f
f(1)
How can I adjust this later code to work as the first one?
my_module.py:
y = 1
def f(x, y = None):
if y is None:
y = globals()['y']
sum = x+y
return sum
test.py
import my_module
my_module.y = 2
f = my_module.f
print(f(1))

how to build generic sum of python function results

I would like to build the sum of functions in python. However, I don't know upfront the length of the sum. All functions are of similar type, i.e. having one input and same output type. For two something like this would work
In [180]: def H(f, g):
...: def _h(x):
...: return f(x) + g(x)
...: return _h
However, I would like to have something which is generic in the sense that I could write H(*args) and it returns me the sum of all function in args (also working for just one).
Am I correct that this is the only way to build sum of functions? I can't write something like h = f+g for two function ?
It is probably easier to write something that is extendable. And you should use the built-in function sum to do the actual summing. This returns a generator that applies each function to the input x:
def map_funcs(x, *funcs):
return (f(x) for f in funcs)
funcs = lambda x: x + 1, lambda x: x**2
x = 10
print(sum(map_funcs(x, *funcs)))
If you want to you can also make it a wrapper which returns something callable, similar to what you've already got:
def map_funcs(*funcs):
def wrapper(x):
return (f(x) for f in funcs)
return wrapper
funcs = lambda x: x + 1, lambda x: x**2
x = 10
print(sum(map_funcs(*funcs)(x)))
# 111
Yes, it's possible. You have to use the sum() builtin function that return the sum of all values in the given list. Before that, you of course have to compute the list of all the functions givent to H() run with the correct parameter:
def power_two(x):
return x**2
def plus_20(x):
return x + 20
def H(*args):
def _h(x):
_results = [f(x) for f in args]
return sum(_results)
return _h
if __name__ == '__main__':
the_func = H(power_two, plus_20)
final_result = the_func(2)
print("(2^2) + (2+20) = %s" % the_func(2))
print("(3^2) + (3+20) = %s" % the_func(3))
Returns:
(2^2) + (2+20) = 26
(3^2) + (3+20) = 32
Try this:-
def H(*args):
def _h(x):
for func in args:
z += func(x)
return z
return _h
Just loop around the functional arguments and then sum it. I guess simple?
I hope it helps!

How to repeat a function n times

I'm trying to write a function in python that is like:
def repeated(f, n):
...
where f is a function that takes one argument and n is a positive integer.
For example if I defined square as:
def square(x):
return x * x
and I called
repeated(square, 2)(3)
this would square 3, 2 times.
That should do it:
def repeated(f, n):
def rfun(p):
return reduce(lambda x, _: f(x), xrange(n), p)
return rfun
def square(x):
print "square(%d)" % x
return x * x
print repeated(square, 5)(3)
output:
square(3)
square(9)
square(81)
square(6561)
square(43046721)
1853020188851841
or lambda-less?
def repeated(f, n):
def rfun(p):
acc = p
for _ in xrange(n):
acc = f(acc)
return acc
return rfun
Using reduce and lamba.
Build a tuple starting with your parameter, followed by all functions you want to call:
>>> path = "/a/b/c/d/e/f"
>>> reduce(lambda val,func: func(val), (path,) + (os.path.dirname,) * 3)
"/a/b/c"
Something like this?
def repeat(f, n):
if n==0:
return (lambda x: x)
return (lambda x: f (repeat(f, n-1)(x)))
Use an itertools recipe called repeatfunc that performs this operation.
Given
def square(x):
"""Return the square of a value."""
return x * x
Code
From itertools recipes:
def repeatfunc(func, times=None, *args):
"""Repeat calls to func with specified arguments.
Example: repeatfunc(random.random)
"""
if times is None:
return starmap(func, repeat(args))
return starmap(func, repeat(args, times))
Demo
Optional: You can use a third-party library, more_itertools, that conveniently implements these recipes:
import more_itertools as mit
list(mit.repeatfunc(square, 2, 3))
# [9, 9]
Install via > pip install more_itertools
Using reduce and itertools.repeat (as Marcin suggested):
from itertools import repeat
from functools import reduce # necessary for python3
def repeated(func, n):
def apply(x, f):
return f(x)
def ret(x):
return reduce(apply, repeat(func, n), x)
return ret
You can use it as follows:
>>> repeated(os.path.dirname, 3)('/a/b/c/d/e/f')
'/a/b/c'
>>> repeated(square, 5)(3)
1853020188851841
(after importing os or defining square respectively)
I think you want function composition:
def compose(f, x, n):
if n == 0:
return x
return compose(f, f(x), n - 1)
def square(x):
return pow(x, 2)
y = compose(square, 3, 2)
print y
Here's a recipe using reduce:
def power(f, p, myapply = lambda init, g:g(init)):
ff = (f,)*p # tuple of length p containing only f in each slot
return lambda x:reduce(myapply, ff, x)
def square(x):
return x * x
power(square, 2)(3)
#=> 81
I call this power, because this is literally what the power function does, with composition replacing multiplication.
(f,)*p creates a tuple of length p filled with f in every index. If you wanted to get fancy, you would use a generator to generate such a sequence (see itertools) - but note it would have to be created inside the lambda.
myapply is defined in the parameter list so that it is only created once.

What do double parentheses mean in a function call? e.g. func(foo)(bar)

I use this idiom all the time to print a bunch of content to standard out in utf-8 in Python 2:
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
But to be honest, I have no idea what the (sys.stdout) is doing. It sort of reminds me of a Javascript closure or something. But I don't know how to look up this idiom in the Python docs.
Can any of you fine folks explain what's going on here? Thanks!
.getwriter returns a function callable object; you are merely calling it in the same line.
Example:
def returnFunction():
def myFunction():
print('hello!')
return myFunction
Demo:
>>> returnFunction()()
hello!
You could have alternatively done:
>>> result = returnFunction()
>>> result()
hello!
Visualization:
evaluation step 0: returnSomeFunction()()
evaluation step 1: |<-somefunction>-->|()
evaluation step 2: |<----result-------->|
codecs.getwriter('utf-8') returns a class with StreamWriter behaviour and whose objects can be initialized with a stream.
>>> codecs.getwriter('utf-8')
<class encodings.utf_8.StreamWriter at 0x1004b28f0>
Thus, you are doing something similar to:
sys.stdout = StreamWriter(sys.stdout)
Calling the wrapper function with the double parentheses of python flexibility.
Example:
funcwrapper
def funcwrapper(y):
def abc(x):
return x * y + 1
return abc
result = funcwrapper(3)(5)
print(result)
funcWrapper
def xyz(z):
return z + 1
def funcwrapper(y):
def abc(x):
return x * y + 1
return abc
result = funcwrapper(3)(xyz(4))
print(result)

Categories