how to override inner method function in outer - python

How to modify the code
def mackfunc(a):
def func(b):
return a+b
return func
f = mackfunc(1)
print(f(1))
print(f(2))
The output is 2 and 3
def mackfunc(a):
def func(b):
return a+b
return func
f = mackfunc(1)
add sth here to this out
print(f(1))
print(f(2))
I hope that the output here is 3 and 4

You can't. func is a local variable, which cannot be interfered with from outside the function. You can either redefine mackfunc entirely, or wrap it.
# redefine
def mackfunc(a):
def func(b):
return a + b + 1
return func
# wrap
orig_mackfunc = mackfunc
def mackfunc(a):
orig_func = orig_mackfunc(a)
def func(b):
return orig_func(b) + 1
return func

You can use a custom function inside you inner function and then redefine it later
def custom(arg):
return arg
def mackfunc(arg):
def func(b):
return custom(arg)+b
return func
f = mackfunc(1)
print(f(1))
print(f(2))
print()
def newcustom(arg):
return arg + 1
custom = newcustom
print(f(1))
print(f(2))
OUTPUT
2
3
3
4
Hope this helps. :)

Related

List of functions->single function (in python)

Say that I have a list of functions: [f1, f2, f3] (in python)
How do I return a single function F:=f3(f2(f1())) (notice that F is of function type). I know that it's possible to do it with .reduce() but I was wondering if there's another way to do it without using libraries.
edit:
Also, notice that the length of the list can be greater than 3
I tried:
def func(list):
i = 1
new_function = filters[0]
while i<=len(filters)-1:
new_function = filters[i](new_function)
i+=1
return new_function
but it doesn't work
The problem in your code is that you pass a function as argument with filters[i](new_function).
I would suggest this recursive solution:
def chain(first, *rest):
return lambda x: first(chain(*rest)(x) if rest else x)
Example use:
def inc(x):
return x + 1
def double(x):
return x * 2
def square(x):
return x * x
f = chain(square, double, inc)
print(f(5)) # ((5+1)*2) ** 2 == 144
I see that in the code you tried, you never actually call the first of your functions. (I also assume that your code starts: def func(filters):
Taking into account that f1() takes no parameter, but the rest take the parameter of the return of the previous function, this should work:
def fit(funcs):
v = funcs[0]()
for f in funcs[1:]:
v = f(v)
return v
def f1():
return 42
def f2(x):
return x
def f3(x):
return x
fs = [f1, f2, f3]
a = lambda:fit(fs)
print(a())
Output: 42
def get_single_func(func_list):
def single_func(*args, **kwargs):
ret = func_list[0](*args, **kwargs)
for func in func_list[1:]:
ret = func(ret)
return ret
return single_func

Trying to create a function that repeats a function

I have a helping function:
def incr(x):
return x+1
I want to create a function named "repeated" that use "incr" function n times on a certain parameter
In the end I want to use the "repeated" function in this matter only :
repeated (incr, 4)(2)
That for example will output 6.
So far I tried to do this:
def repeated(f, n):
func, x = f
for i in range(n):
func(x)
But it gave me an error saying I can't unpack a non Tuple function.
It doesn't seem like I don't have access in the function to the "(2)"
I do not recommend to use such a syntax construct, for such a task:
repeated(incr, 4)(2)
Your repeated function must return another function, that will be called by (2).
This should work in your requested manner:
def incr(x):
return x+1
def repeated(f, x):
# function foo will be returned by repeated and called by (2)
def foo(n):
res = x
for i in range(n):
res = f(res)
return res
return foo
print(repeated(incr, 4)(2))
I think you may want to do something like functional programming.
Add args to deal with for different kind of function you want to repeat.
I can't confirm if there is a position argument what kind of results you want, so I didn't deal with it.
code:
import functools
def incr(x):
return x + 1
def incx(x,y = 0):
return x + y + 1
def repeated_inner(func,args,times):
head, *rest = args
for _ in range(times):
head = func(head, *rest)
return args[0]
def repeated(func, *args ):
return functools.partial(repeated_inner, func, args)
print(repeated(incr, 4)(2))
print(repeated(incx, 4)(2))
print(repeated(incx, 4 ,3)(2))
result
6
6
12
the repeatedfunction must return a function
def repeated(func, n):
def repeatedfunc(x):
rsl = x
for i in range(n):
rsl = func(rsl)
return rsl
return repeatedfunc
def incr(x):
return x+1
rslt = repeated(incr, 4)(2)
print(rslt)
output
6
You should write something like this:
def repeated(f, arg_0, n):
arg = arg_0
for i in range(n):
arg = f(arg)
return arg
In a more general situation:
def repeated(f, arg):
def n_f(n):
result = 0
for i in range(n):
result =f(arg)
return result
return n_f

Reuse logic in Python functions that involve Return

I have a long list of functions that all have the same initial part.
default_value = 123
def func_1(input):
if apply_some_check(input):
return default_value
return do_something_1(input)
def func_2(input):
if apply_some_check(input):
return default_value
return do_something_2(input)
def func_3(input):
if apply_some_check(input):
return default_value
return do_something_3(input)
......
Is there any way to reuse the
if apply_some_check(input):
return default_value
part of the code, while keeping this list of functions (required by my code reviewer for readability)?
You can use decorators for this.
def checked(f):
def inner(inp):
if apply_some_check(inp):
return default_value
return f(inp)
return inner
# checked takes a function and returns a function, we can now use it as a function decorator
#checked
def some_func(inp):
return do_something(inp)
You could also try to use partial if it fits to your needs as follows:
from functools import partial
default_value = 123
def apply_some_check(a):
return False
def func_template(do_something, a):
if apply_some_check(a):
return default_value
return do_something(a)
def do_something_1(a):
return "test1" == a
def do_something_2(a):
return "test2" == a
def do_something_3(a):
return "test3" == a
if __name__ == '__main__':
a = "test2"
funcs = []
for i in range(1, 4):
funcs.append(partial(func_template, eval(f"do_something_{i}"), a))
for f in funcs:
print(f())
Result:
False
True
False

Simple way to count the number of times def f(x) is evaluated?

I am trying to count the number of times that f(x) is evaluated without having to change my code too much, it doesn't seem like it should be very difficult but I can't seem to figure it out.
def f (x):
f = 12*x**5-45*x**4+40*x**3+5
return f
def bounding():
d=.1
x=6
n=0
while(n<50):
Lb=x-d
n+=1
Ub=x+d
if f(Lb)>=f(x) and f(Ub)<=f(x):
x=x+d
elif f(Lb)<=f(x) and f(Ub)>=f(x):
x=x-d
elif f(Lb)>=f(x) and f(Ub)>=f(x):
print("Lower bound:",Lb,"Upperbound:",Ub)
break
print (n)
bounding()
A decorator based solution, that you can apply to any function you want...
def count(fn):
def wrapper(*args, **kwargs):
wrapper.called+= 1
return fn(*args, **kwargs)
wrapper.called= 0
wrapper.__name__= fn.__name__
return wrapper
#count
def test():
print "something"
test()
print test.called #will print 1
class F:
count = 0
def __call__(self, x):
self.count += 1
return 12*x**5-45*x**4+40*x**3+5
f = F()
From here on as before and the count is given by f.count. Tested :)
>>> f = F()
>>> f(1)
12
>>> f(2)
-11
>>> f.count
2
>>> f(2)
-11
>>> f.count
3

how to insert new variable in (*args,**kwargs) section?

i want to make a decoration method to assign the variable which the function would use but wouldn't be deliver by itself.
for example add new variable y in lambda r,i wrote code in this way but didn't work.
r = lambda x:x+y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(y=y,*args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
this wouldn't work too
r = lambda x:x+y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(*args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
kwargs is a casual python dict type, so you can just set the value of the y key to be 3
r = lambda x, y=0:x+y
def foo(func):
def wrapped(*args,**kwargs):
print type(kwargs) # will output <type 'dict'>
kwargs['y'] = 3
return func(*args,**kwargs)
return wrapped
In Understanding kwargs in Python this is explained in details.
Problem is that the function r can accept only one argument, you need to change its definition to accept more args:
r = lambda x, y=0, *args, **kwargs: x + y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(y=y, *args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
#447

Categories