This question already has answers here:
Assign multiple functions to a single variable?
(3 answers)
Closed 6 years ago.
The problem is as follows below:
Write a function compose that takes two functions as argument, we call them Fa and Fb, and returns a function, Fres, that means that outdata from the other function is indata to the first, ex: Fres(x) = Fa(Fb(x)).
run example:
>>> def multiply_five(n):
... return n * 5
...
>>> def add_ten(x):
... return x + 10
...
>>> composition = compose(multiply_five, add_ten)
>>> composition(3)
65
>>> another_composition = compose(add_ten, multiply_five)
>>> another_composition(3)
25
So as I understand this if I send in 3 the function compose will take 3+10 = 13
after that send that result into the multiply function it will do: 13*5 witch is 65.
this is the code I've written so far:
def multiply_five(n):
return n*5
def add_ten(x):
return x+10
def compose(func1, func2):
def comp(arg):
return func2(arg)
return func1(comp(arg))
I get compile error, and I've tried some different approaches:
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
composition = compose(multiply_five, add_ten)
File "C:\Users\Jim\Desktop\tdp002\5h.py", line 10, in compose
return func1(comp(arg))
NameError: name 'arg' is not defined
You don't want to call either func1 or func2 yet; you just want to return a function that will call them both.
def compose(func1, func2):
def _(*args, **kw):
return func1(func2(*args, **kw))
return _
You could also just use a lambda expression to create the composed function.
def compose(func1, func2):
return lambda *args, **kw: func1(func2(*args, **kw))
Try this:
def compose(func1, func2):
def comp(arg):
return func1(func2(arg))
return comp
Related
This was the program for our test and I couldn't understand what is going on. This problem is called nested function problem.
def foo(a):
def bar(b):
def foobar(c):
return a + b + c
return foobar
return bar
a, b, c = map(int,input().split())
res = foo(a)(b)(c)
print(res)
I have tried to debug this program but couldn't get any idea about why it is working.
Why is foo(a)(b)(c) not giving an error?
Why it is working and what it is called?
This is a closures concept, Inner functions are able to access variables of the enclosing scope.
If we do not access any variables from the enclosing scope, they are just ordinary functions with a different scope
def get_add(x):
def add(y):
return x + y
return add
add_function = get_add(10)
print(add_function(5)) # result is 15
Everything in Python is an object, and functions as well, so you can pass them as arguments, return them, for example:
def inc(var):
return var + 1
def my_func():
return inc
my_inc = my_func()
print(my_inc) # <function inc at ...>
print(my_inc(1)) # 2
Moreover it's closed to decorator's concept:
def log_this(func):
def wrapper(*args, **kwargs):
print('start', str(args))
res = func(*args, **kwargs)
return res
return wrapper
#log_this
def inc(var):
return var + 1
print(inc(10))
How do you make a partial function that calls like this: function(func , arg1)(arg2). And why/how are you able to do this.
f(x)(y).
x = (func , arg1)
y = (arg2)
I thought I tried using decorators to pass a parameter. I can call the wrapper and it works when I call adder(5), for example.
def partial(arg):
def add(func):
def wrapper(x):
return arg + func(x)
return wrapper
return add
#partial(1)
def adder(z):
return z
adder(4)
a = adder(4)
partial(a, 4)(5) /////////
###///////////////////////////////another format ///////////
def decorator(func , x):
def wrapper(y):
return func(y) + x
return wrapper
def adder(z):
return z
adder = decorator(adder , 2)
#########I can call the wrapper, but I get a local error when I call a partial function.
Can call the wrapper, but I get a local error when I call a partial function.
I want to be able to get the sum of two or more numbers using partial functions.
If you don't want to use functools.partial try e.g a lambda function adder = lambda x: lambda y: x+y or
def adder(x):
def g(y):
return x+y
return g
That should do the job.
You mentioned you want to get the sum of several arguments using partial functions, try:
def adder(*summands):
def h(*more_summands):
return sum(list(summands)+list(more_summands))
return h
If you want to implement the partial application of arguments to an arbitrary function f here is what you can do
partial = lambda f, *args1, **kwargs1: lambda *args2, **kwargs2: \
f(*args1,*args2, **kwargs1, **kwargs2)
Background
I'm using pdfquery to scrap data from pdfs. Like this one. This questions builds off my earlier question here.
I have successfully been able to use custom wrapper functions that can take arguments as seen in this answer. Except for the following which is giving me trouble when I try to run it multiple times in jupyter notebook;
Cell 1
import pdfquery
def load_file(PDF_FILE):
pdf = pdfquery.PDFQuery(PDF_FILE)
pdf.load()
return pdf
file_with_table = 'path_to_the_file_mentioned_above.pdf'
pdf = load_file(file_with_table)
Cell 2
def in_range(prop, bounds):
def wrapped(*args, **kwargs):
n = float(this.get(prop, 0))
return bounds[0] <= n <= bounds[1]
return wrapped
def is_element(element_type):
def wrapped(*args, **kwargs):
return this.tag in element_type
return wrapped
def str_len(condition):
def wrapped(*args, **kwargs):
cond = ''.join([str(len(this.text)),condition])
return eval(cond)
return wrapped
Cell 3
x_check = in_range('x0', (97, 160))
y_check = in_range('y0', (250, 450))
el_check = is_element(['LTTextLineHorizontal', 'LTTextBoxHorizontal'])
str_len = str_len('>0')
els = pdf.pq('LTPage[page_index="0"] *').filter(el_check)
els = els.filter(str_len)
els = els.filter(x_check)
els = els.filter(y_check)
[(i.text) for i in els]
The function, str_len, will work fine if it is run a single time after definition;
No error when running the third cell pictured
but throws a NameError when I try to run the function a second time;
NameError after running third cell a second time.
Here is the text of the NameError
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-27-54cd329bb1e1> in <module>()
2 y_check = in_range('y0', (250, 450))
3 el_check = is_element(['LTTextLineHorizontal', 'LTTextBoxHorizontal'])
----> 4 str_len = str_len('>0')
5
6 els = pdf.pq('LTPage[page_index="0"] *').filter(el_check)
<ipython-input-25-654bff7d0eed> in wrapped(*args, **kwargs)
12 def str_len(condition):
13 def wrapped(*args, **kwargs):
---> 14 return eval(''.join([str(len(this.text)),condition]))
15 return wrapped
NameError: name 'this' is not defined
Questions
Why can I only use this function once after it's definition?
Is there anyway that I can circumvent this problem?
Function names are variables like any other; there isn't a separate namespace for functions. str_len = str_len('>0') rebinds the name str_len to the return value of the call to the original value of str_len. After this line, you no longer have a reference to the function. Use a different name for the computed length:
new_name = str_len('>0')
Sorry if I did not explain myself clearly.
I would like to create a wrapper to call pre-defined functions with different number of inputs. Of course, I can create an individual wrapper for each function, but I am wondering if there is a way to create a generic wrapper for all cases.
The functions that should be called are named 'fun1' and 'fun2' with different number of inputs. I need to create a wrapper 'fun_wrap(func_name, uncertain amount of inputs)', which only needs the function name to be called and its associated amount of inputs.
One more thing, I need to change the input names by adding '_in' and make them global variables first. Below is my broken code. Thanks for any suggestions!
def fun1(a,b):
return a+b
def fun2(a,b,c):
return a*b/c
def set_globals(**kwargs):
for argname in kwargs:
globals()['%s_in' % argname] = kwargs[argname]
def fun_wrap(func_name, uncertain amount of inputs):
ffunc_name(set_globals(uncertain amount of inputs))
In this way, if I can call final_fun with arguments like:
fun_wrap(fun1,a,b)
fun_wrap(fun2,a,b)
UPDATE
I tried to use *arg, but failed...
def fun1(a,b):
return a+b
def fun2(a,b,c):
return a*b/c
def set_globals(**kwargs):
for argname in kwargs:
globals()['%s_in' % argname] = kwargs[argname]
def fun_wrap(func_name, *arg):
func_name(set_globals(*arg))
fun_wrap(fun2,a=1,b=2,c=3)
got error:
Traceback (most recent call last):
File "D:\Dropbox\AppPest\rice\try.py", line 19, in <module>
fun_wrap(fun2,a=1,b=2,c=3)
TypeError: fun_wrap() got an unexpected keyword argument 'a'
def fun1(a,b):
return a + b
def fun2(a,b,c):
return a * b / c
def set_globals(**kwargs):
for argname in kwargs:
globals()['%s_in' % argname] = kwargs[argname]
def fun_wrap(func, **kwargs):
set_globals(**kwargs) # made the call to set_globals before calling your function
return func(**kwargs) # return the value returned by the functions called
Working through "Learning Python" came across factory function. This textbook example works:
def maker(N):
def action(X):
return X ** N
return action
>>> maker(2)
<function action at 0x7f9087f008c0>
>>> o = maker(2)
>>> o(3)
8
>>> maker(2)
<function action at 0x7f9087f00230>
>>> maker(2)(3)
8
However when going deeper another level I have no idea how to call it:
>>> def superfunc(X):
... def func(Y):
... def subfunc(Z):
... return X + Y + Z
... return func
...
>>> superfunc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: superfunc() takes exactly 1 argument (0 given)
>>> superfunc(1)
<function func at 0x7f9087f09500>
>>> superfunc(1)(2)
>>> superfunc(1)(2)(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
>>> superfunc(1)(2)
>>>
Why doesn't superfunc(1)(2)(3) work while maker(2)(3) does?
While this kind of nesting certainly doesn't look like a good, usable code to me, Python still accepts it as valid, so I'm curious as to how this can be called.
You get a TypeError because function func doesn't return anything (thus its return is NoneType). It should return subfunc:
>>> def superfunc(X):
... def func(Y):
... def subfunc(Z):
... return X + Y + Z
... return subfunc
... return func
...
A return is missing somewhere in your superfunc: you have a return for subfunc, but none for func.
superfunc corrected, with a calling example
def superfunc(X):
def func(Y):
def subfunc(Z):
return X + Y + Z
return subfunc
return func
print superfunc(1)(2)(3)
You forgot the return of the second function.
Here is the fixed function
def superfunct(x):
def func(y):
def subfunc(z):
return x + y + z
return subfunc
return func
print superfunct(1)(2)(3)