How to combine two functions in Python - python

I want to combine any two functions, funcA and funcB, so they create one function that take the input of funcB, send the result to funcA and return that result
funcC(args) = funcA(funcB(args))
For example:
def sub(a, b):
return a - b
def neg(a):
return -a
For this example, my question is how to create a negsub function such that
negsub(3, 4) = 1 # neg(sub(3, 4)) = 1
negsub(2, 0) = -2 # neg(sub(2, 0)) = -2
and so on.

This is probably the most straightforward way:
def negsub(a, b):
return neg(sub(a, b))
But if you want a function that builds functions out of other functions:
def combine(outer, inner):
return lambda *args: outer(inner(*args))
Now you can do:
negsub = combine(neg, sub)
negsub(3, 4)

def sub(a, b):
return a - b
def neg(a):
return -a
def negsub(a, b):
return neg(sub(a, b))

Related

Using Python decorators to take modulus of results

I'm learning decorators in Python, and I came across some trouble with a decorator I'm using:
#curry
def modulo(mod,f):
if mod:
#fun.wraps(f)
def wrapper(*args, **kw):
result = f(*args, **kw)
return tuple(r % mod for r in result)
else:
return f
return wrapper
The curry decorator is a simple currying, so I can call mod as an argument in the following:
def _fib(p=1,q=-1,mod=None):
''' Fibonacci sequence '''
#modulo(mod)
def next_fib(pair):
x,y = pair
return y, p*x - q*y
yield from ( y for x,y in iterate(next_fib,(1,0)) )
which works and looks nice and clean. However, say I wanted another [closely related] generator for Lucas sequences:
def _luc(p=1,q=-1,mod=None):
''' Lucas sequence '''
#modulo(mod)
def next_luc(pair):
x,y = pair
return y, p*x - q*y
yield from ( y for x,y in iterate(next_luc,(p-2,2)) )
If I call them together, I get some sort of collision:
>>> F = _fib()
>>> print(take(10,F))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
>>> L = _luc()
>>> print(take(10,L))
" ... TypeError: cannot unpack non-iterable function object"
Called individually they work as expected, with the correct modular terms returned.
My question twofold:
is this a namespace collision where they are both referring to modulo()?
How would you go about doing something like this?
helper functions:
import itertools as it
import functools as fun
def curry(f):
argc = f.__code__.co_argcount
f_args = []
f_kwargs = {}
#fun.wraps(f)
def wrapper(*args, **kwargs):
nonlocal f_args, f_kwargs
f_args += args
f_kwargs.update(kwargs)
if len(f_args)+len(f_kwargs) == argc:
return f(*f_args, **f_kwargs)
else:
return wrapper
return wrapper
def iterate(f,x):
''' x, f(x), f(f(x)), f(f(f(x))), ... '''
return it.accumulate(it.repeat(x), lambda fx, _: f(fx))
def take(n,iterable):
return [x for x in it.islice(iterable,n)]
I found that extending the original modulo wrapper does the trick!
With thanks to Thomas_Breydo for suggesting to change up the curried function
def modulo(mod):
def wrapper(f):
#fun.wraps(f)
def deco(*args,**kwargs):
if mod:
return tuple(n%mod for n in f(*args,**kwargs) )
else:
return f(*args,**kwargs)
return deco
return wrapper
which resolves my issue.

List comprehension based on choices

Basically, if I were to write a function with variable return elements, like so:
def func(elem1=True, elem2=True, elem3=True, elem4=False):
x = MyClass()
ret = []
if elem1:
ret.extend([x.func1()])
if elem2:
ret.extend([x.obj1])
if elem3:
ret.extend([x.func2().attr1])
if elem4:
ret.extend(x.list_obj3)
return ret
Things get rather long and windy. Is it possible to do something like this perhaps:
def func(elem1=True, elem2=True, elem3=True, elem4=False):
x = MyClass()
return [x.func1() if elem1,
x.obj1 if elem2,
x.func2().attr1 if elem3,
x.list_obj3 if elem4]
How neat is that!?
I know this can be done:
def func(elem1=True, elem2=True, elem3=True, elem4=False):
x = MyClass()
ret = [x.func1(), x.obj1, x.func2().attr1, x.list_obj3]
choices = [elem1, elem2, elem3, elem4]
return [r for i, r in enumerate(ret) if choices[i]]
but I would like to not calculate the elements if the user does not want them; it is a little expensive to calculate some of them.
If you hide your operations in lambdas then you can use lazy evaluation:
def func(elem1=True, elem2=True, elem3=True, elem4=False):
x = MyClass()
return [L() for inc,L in (
(elem1, lambda: x.func1()),
(elem2, lambda: x.obj1),
(elem3, lambda: x.func2().attr1),
(elem4, lambda: x.list_obj3),
) if inc]
Asking a slightly different question, can you get behaviour like matlab/octave, where you only calculate the first two results if you are assigning to two variables, without computing results 3 and 4?
For example:
a, b = func()
Python can't quite do it since func() doesn't know how many return values it wants, but you can get close using:
from itertools import islice
def func():
x = MyClass()
yield x.fun c1()
yield x.obj1
yield x.func2().attr1
yield x.list_obj3
a, b = islice(func(), 2)
I'm not sure it is better, but you could add array indexing semantics using a decorator, which would allow you to write:
#sliceable
def func():
...
a, b = func()[:2]
This is easy enough to implement:
from itertools import islice
class SlicedIterator(object):
def __init__(self, it):
self.it = it
def __iter__(self):
return self.it
def __getitem__(self, idx):
if not isinstance(idx, slice):
for _ in range(idx): next(self.it)
return next(self.it)
return list(islice(self.it, idx.start, idx.stop, idx.step))
def sliceable(f):
def wraps(*args, **kw):
return SlicedIterator(f(*args, **kw))
return wraps
Testing:
#sliceable
def f():
print("compute 1")
yield 1
print("compute 2")
yield 2
print("compute 3")
yield 3
print("compute 4")
yield 4
print("== compute all four")
a, b, c, d = f()
print("== compute first two")
a, b = f()[:2]
print("== compute one only")
a = f()[0]
print("== all as a list")
a = f()[:]
gives:
== compute all four
compute 1
compute 2
compute 3
compute 4
== compute first two
compute 1
compute 2
== compute one only
compute 1
== all as a list
compute 1
compute 2
compute 3
compute 4

How to pass an empty parameter to a python function?

Here is the working code:
def g(y=10):
return y**2
def f(x,y=10):
return x*g(y)
print(f(5)) #->500
However, let's suppose we don't want to remember and copy a default value of keyword parameter y to the definition of external function (especially if there are several layers of external functions). In the above example it means that we want to use parameter, already defined in g.
One way to do that:
def f(x,y=None):
if y==None: return x*g()
else: return x*g(y)
But is there a cleaner way to do the same?
Something like:
def f(x,y=empty()):
return x*g(y)
Interesting question! Here's another possibility, however this requires handing in the second parameter as a named parameter.
>>> def g(y=10):
... return y**2
...
>>> def f(x, **kwargs):
... return x * g(**kwargs)
...
>>> f(5)
500
>>> f(5, y=0)
0
A limitation of signatures such as def f(x, y=None) or def f(x, **kwargs) is that readers have to dig into source code or documentation to find out what's going on with y. Stick to something simple and straightforward:
DEFAULT_Y = 10
def g(y=DEFAULT_Y): ...
def f(x, y=DEFAULT_Y): ...
This is possible:
def g(y=10):
return y**2
def f(x, y=g.__defaults__[0]):
return x * g(y)
But it is arguably less clear than what you had originally (defaulting y to None).
An option which doesn't restrict the definition order of f and g, and should remain working if the function default of g gets changed dynamically:
def f(x, y=None):
kwargs = {}
if y is None:
kwargs['y'] = y
return x * g(**kwargs)
I'd like to start by saying if the arguments were keyword only this would be so easy:
def f(*, x="x", y= "y",z="z"):
print(x,y,z)
def g(*, x,y,z):
print(x,y,z,"from g!!")
if g.__kwdefaults__ is None: #completely override defaults
g.__kwdefaults__ = f.__kwdefaults__
else: #if there are already some defaults then update
g.__kwdefaults__.update(f.__kedefaults__)
g()
if you are using positional arguments it isn't quite as easy although your example is one of the specific cases that works the same way:
def g(y=10): #last argument is y
return y**2
def f(x,y): #last argument is y
return x*g(y)
f.__defaults__ = g.__defaults__ #copies the end of the defaults to f
print(f(5)) #->500
But this is a very specific case:
The arguments to inherit the defaults must be in the same order as the original.
There must not be any positional arguments after the ones with inherited defaults
There must not be any other arguments with default values (or they get overridden)
The generic solution requires quite a bit of code but allows any signature to be merged into another, for example:
def f(x,y,z=0,reverse=True):
pass
#copy_defaults(f)
def g(a,b, #arguments for g
x,y,z, #arguments to forward to f
c=None, d="test", #some optional arguments for g
*,reverse): #only take reverse as a keyword
pass
>>> inspect.signature(g)
<Signature (a, b, x, y, z=0, c=None, d='test', *, reverse=True)>
This can be achieved with the following code (I can't find a simpler way to do it that works with above case)
import inspect
def copy_defaults(original_f):
"creates wrapper for DefaultArgs(original_f).copy_defaults(dest_f)"
def wrapper(dest_f):
return DefaultArgs(original_f).copy_defaults(dest_f)
return wrapper
class DefaultArgs(dict):
def __init__(self,func):
spec = inspect.getfullargspec(func)
if spec.defaults:
dict.__init__(self,
zip(reversed(spec.args),
reversed(spec.defaults)
))
else:
dict.__init__(self) #I'm not sure this is necessary
if spec.kwonlydefaults:
self.update(spec.kwonlydefaults)
def get_kwdefaults(self,keywords):
return {k:v for k,v in self.items() if k in keywords}
def gen_pos_defaults(self,args,defaults=None):
if defaults is None:
defaults = ()
found_default = False
for i,arg in enumerate(args,start=len(defaults)-len(args)):
if arg in self:
yield self[arg]
found_default = True
elif i>=0:
yield defaults[i]
elif found_default: #if an argument does not have a default but is after one that does
raise TypeError("non-default argument %r follows default argument"%arg)
def copy_defaults(self,func):
spec = inspect.getfullargspec(func)
new_kwargs = self.get_kwdefaults(spec.kwonlyargs)
if func.__kwdefaults__ is not None:
func.__kwdefaults__.update(new_kwargs)
else:
func.__kwdefaults__ = new_kwargs
func.__defaults__ = tuple(self.gen_pos_defaults(spec.args,spec.defaults))
return func
If you can modify g, then this works:
def g(y=None):
if y is None:
y = 10
return y**2
def f(x,y=None):
return x*g(y)

Passing arguments down recursive functions

I want to pass an argument from the first call of a recursive function down to the later ones:
Example:
def function(x):
if base_case:
return 4
else:
return function(x_from_the_first_call + x_from_this_call)
Is there any better way of doing this than a closure?
E.g.
def function(outer_x):
def _inner(x)
if base_case:
return 4
else:
return function(outer_x + x)
return _inner(outer_x)
If you will change x somehow in function, then this should work i think:
def function(x, *args):
if base_case:
return 4
else:
new_x = x+1 # some change to x
if args:
# in args all previous x values
# remove if in case if you need all previous values
if not args:
args.append(x)
return function(new_x, *args)

Call several functions and return the collective result

I want to call some functions to a single value and return the collective result.
class Foo:
def __init__(self, i):
self.i = i
def get(self):
return self.fn1(self.fn2(self.i)) #200
def fn1(self, i):
return i + i #10+10 = 20
def fn2(self, i):
return i * i #20*20 = 200
#...
foo = Foo(10)
print(foo.get())
Is there a more elegant way or pattern?
Here is my try to improve this a little bit.
def fn1(i):
return i + i #10+10 = 20
def fn2(i):
return i * i #20*20 = 200
def get(i):
funcs = [fn2, fn1]
for f in funcs:
i = f(i)
return i
print(get(10))
In general, nesting functions as you do above is the most straightforward and readable way to compose functions in Python.
If you're composing many functions, it might be worth writing a compose function.
def compose(*funcs):
if len(funcs) == 1:
return funcs[0]
else:
def composition(*args, **kwargs):
return funcs[0](compose(*funcs[1:])(*args, **kwargs))
return composition
Or, if you prefer an iterative over a recursive solution:
def compose_pair(f1, f2):
def composition(*args, **kwargs):
return f1(f2(*args, **kwargs))
return composition
def compose_iterative(*funcs):
iterfuncs = iter(funcs)
comp = next(iterfuncs)
for f in iterfuncs:
comp = compose_pair(comp, f)
return comp
Personally, two of my favorite python functions are map and reduce.
def get(i):
return reduce(lambda acc, f: f(acc), [i,fn2,fn1] )
def fn1(i):
return i + i #10+10 = 20
def fn2(i):
return i * i #20*20 = 200
print( get(10) ) # 200
You could use a decorator-style solution:
class Base()
def __init__(self, decorated):
self.decorates = decorated
def foo(self, arg):
if self.decorates:
arg = self.decorates.foo( arg )
return self._do_foo( arg )
def _do_foo(self, arg):
return arg
Your implementations will inherit from Base and implement _do_foo().
You set it up like this:
a = Subclass(None)
b = AnotherSublcass( a )
c = YetAnotherSubclass( b )
all of the Sublcasses inherit from Base. when you call c.foo( arg ), you'll get the result passed through all three _do_foo() methods.

Categories

Resources