How to concat multiple functions in python - python

How to do this in python?
def f(a, b):
return a, b+2, b+3
def g(a, b, c):
return a+b+c
How to get something like k = f+g hence that
k(a, b) is g(f(a,b))
Note that this is an abstract question. I wonder whether there's a function that can return a concat of f+g or even concat([...]) generally working regardless of the args of f.
In another word, I want a function whose args is f and g and returns k:
def concat(f,g):
return something_equivalent_to_k_above

Answer for original question
Define:
k = lambda x,y:g(*f(x,y))
Example:
>>> k(2,3)
13
Answer for revised question
Define:
concat = lambda a,b:lambda *args: b(*a(*args))
Example:
>>> k = concat(f,g)
>>> k(2,3)
13

There are at least 2 approaches to do this:
Approach A (recommended):
def compound(inner_func, outer_func):
def wrapper(*args, **kwargs):
return outer_func(*inner_func(*args, **kwargs))
return wrapper
Note that inner_func mustn't return a dictionary, in which case we should write return outer_func(**inner_func(*args, **argv)).
Usage:
def f(a, b):
return a, b+2, b+3
def g(a, b, c):
return a+b+c
k = compound(f, g)
print k(1, 2)
# output: 10
Approach B:
First, define a "decorator factory" like this:
def decorator_factory(inner_func):
def decorator(outer_func):
def wrapper(*args, **kwargs):
return outer_func(*inner_func(*args, **kwargs))
return wrapper
return decorator
Then you can use it like this:
def f(a, b):
return a, b+2, b+3
#decorator_factory(f)
def g(a, b, c):
return a+b+c
print g(1, 2)
# output: 10

Why not define a third function as you did with f and g:
>>> def f(a, b):
return a, b+2, b+3
>>> def g(a,b,c):
return a+b+c
>>> def k(a,b):
return g(*f(a,b))
>>> k(2,3)
13

Related

Access parameters of decorator and of function being decorated

import functools
def test_decorator(a, b, c):
def decorator(function):
#functools.wraps(function)
def wrapper(*args, **kwargs):
return function(*args, **kwargs)
return wrapper
return decorator
#test_decorator(a=1, b=2, c=3)
def test(d, e, f):
return None
The following method will give the arguments of the function being wrapped:
import inspect
fn = test
list(inspect.signature(fn)._parameters)
Will return d, e, f
How can I also access the parameters of the decorator/wrapper test_decorator i.e. a, b, c

passing variables to another DEF

I'm writing a class similar to this one how can I pass values (w,v) to the def q func
class A():
def EM (self,a,b):
self.a=a
self.b=b
w=a+b
print(w)
def number(self,c,d):
self.c=c
self.d=d
v=c-d
print(d)
def q (self,v,w) ##problrm here
qq=v+w
print(qq)
Firstly it helps if you format your code properly as shown:
class A():
def EM (self,a,b):
self.a=a
self.b=b
w=a+b
print(w)
def number(self,c,d):
self.c=c
self.d=d
v=c-d
print(d)
def q (self,v,w) ##problrm here
qq=v+w
print(qq)
But to answer your question you would use the results for EM and number as shown
instance = A()
result = instance.q(instance.EM(a, b), instance.number(c, d))
Because you want to use multiple method results as parameters you have to do it outside of those methods although you could create a new method to make it look better like
class A():
def EM (self,a,b):
self.a=a
self.b=b
w=a+b
return w
def number(self,c,d):
self.c=c
self.d=d
v=c-d
return d
def q (self,v,w)
qq=v+w
return qq
def doThisThing(a, b, c, d):
return self.q(self.EM(a, b), self.number(c, d))
Notice how I've changed the prints to returns as instead of displaying the result to the console we want to pass the result to the caller. If you wanted to now display the result you could use
print(instance.doThisThing(a, b, c, d))
Try this out:
a = A()
a.q(w= '''w''',v= '''v''')

Cooperative multiple inheritance and python 2.7 mixins

I'm trying to use the cooperative multiple inheritance pattern to resolve a problem. A very simplified version of my python 2.7 code looks like this:
class Base1(object):
def __init__(self, a, b):
self.a = a
self.b = b
def to_tuple(self):
return self.a, self.b
def to_string(self):
return '%s.%s' % self.to_tuple() # (1)
class Base2(object):
def __init__(self, c, d):
self.c = c
self.d = d
def to_tuple(self):
return self.c, self.d
def to_string(self):
return '%s-%s' % self.to_tuple() #(2)
class MyMixin(Base1, Base2):
def __init__(self, a, b, c, d):
Base1.__init__(self, a, b)
Base2.__init__(self, c, d)
def to_tuple(self):
return Base1.to_tuple(self) + Base2.to_tuple(self)
def to_string(self):
return '{}: {} '.format(Base1.to_string(self), Base2.to_string(self))
mix = MyMixin('a', 'b', 'c', 'd')
print(mix.to_string())
After writing this code, I was expecting the result:
a.b: c-d
but the code fails. When the line #(1) is run, self is a MyMixin class, not a Base1 class, so to_tuple returns 4 items.
The only way I've found to fix this is to replace the lines #(1) and #(2) above with:
return '%s.%s' % Base1.to_tuple() # (1)
return '%s.%s' % Base2.to_tuple() # (2)
and this feels terribly wrong for a number of reasons.
What am I doing wrong?
Here is what happens. When mix.to_string() is called, first, it calls Base1.to_string(self) passing a mix instance as a self, which means when to_string is called on Base1 it has an instance of MyMixin which returns ('a','b','c','d') on to_tuple call. That's why it fails, cuz tuple contains 4 items and only 2 are required by line #1.
To solve this issue try to avoid inheritance from multiple classes with the same method signatures. Use composition instead.
class MyMixin(object):
def __init__(self, a, b, c, d):
self.base1 = Base1(a, b)
self.base2 = Base2(c, d)
def to_tuple(self):
return self.base1.to_tuple(self) + self.base2.to_tuple(self)
def to_string(self):
return '{}: {} '.format(self.base1.to_string(), self.base2.to_string())

Python **obj.__dict__ equilavent command

I'm wondering if there is any more pythonic call in func_wrap to, without modifying func or the func_wrap header, call the function func?
class Foo(object):
a = 1
b = 2
class Bar(object):
c = 3
def func_wrap(foo_obj, bar_obj):
return func(a=foo_obj.a, b=foo_obj.b, c=bar_obj.c)
def func(a, b, c):
return a + b + c
Something more along the lines of:
def func_wrap(foo_obj, bar_obj):
return func(**foo_obj.__dict__ , **bar_obj.__dict__)
You could use the vars function:
def func_wrap(foo_obj):
return func(**vars(foo_obj))
which comes down to the same thing.

Decorating a function to add custom arguments to function

I am interested in creating a generic function and decorating all other functions with it. The new function will contain arguments from both functions. Example
def decorator(func):
# Some chunk of code
#decorator
def func(a, b):
print a**2, b**2
return a**2, b**2
# Equivalent func of what I want out of the decorator
def equiv_func(a, b, var):
print var # I want to modify all decorated functions to accept a new
# argument and print it using "print var"
print a**2, b**2
return a**2, b**2
This is what I kind of came up with but...
def decor(func):
def modify(var, **kwargs):
print var
x, y = func(**kwargs)
return x, y
return modify
#decor
def func(a, b):
print a**2, b**2
return a**2, b**2
>>> func(var="hi", a=4, b=5)
hi
16 25
I used **kwargs as a way to account for arguments of func, but this forces me to use func(var="hi", a=4, b=5) instead of func(a=4, b=5, var="hi") due to the positioning of **kwargs.
Also, this workaround prevents me from using **kwargs when defining my decorator when I need it since it is already used to input arguments into func. Example
def test(**kwargs):
if 'test_ans' in kwargs:
if kwargs['test_ans'] == 'y':
return True
else:
return False
def decor(func):
def modify(var, **kwargs):
if test(**kwargs): # I need to use **kwargs here, but I also need it to define my
# arguments in func.
print var
x, y = func(**kwargs)
return x, y
return modify
...
# The following is what I expect but due to **kwargs being used for two purposes,
# it doesn't work
>>> func(var='hi', a=4, b=5, test_ans='y')
'hi'
16 25
>>> func(var='hi', a=4, b=5, test_ans='n')
16 25
The examples are just to illustrate of the constraints I face. They are not the actual code (I wouldn't write a test function that uses **kwargs for example).
To put simply, is there any other way to modify func(a, b) to func(a, b, c, d, e, ..., **kwargs) without using kwargs in the decorator?
You can access the parameters that a function accepts with func.func_code.co_varnames. Once you know that, you can filter everything else out.
This is limited in that you would not be able to use this effectively if myfunc accepted **kwargs as a parameter.
def print_decorator(func):
def wrapped(*args, **kwargs):
# a tuple of the names of the parameters that func accepts
func_params = func.func_code.co_varnames
# grab all of the kwargs that are not accepted by func
extra = set(kwargs.keys()) - set(func_params)
for kw in extra:
print kwargs.pop(kw)
return func(*args, **kwargs)
return wrapped
#print_decorator
def myfunc(a, b, c=None):
print 'myfunc was passed: a={}, b={}, c={}'.format(a, b, c)
return a, b, c
>>> myfunc(1, b=2, c=3, d=4, e=5)
4
5
myfunc was passed: a=1, b=2, c=3
You could allow func to be called with
func(a=4, b=5, var="hi")
by making var a keyword argument.
def decor(func):
def modify(*args, **kwargs):
var = kwargs.pop('var', None)
print var
x,y=func(*args, **kwargs)
return x,y
return modify
#decor
def func(a,b):
print a**2,b**2
return a**2,b**2
func(a=4, b=5, var="hi")
func(a=4, b=5)

Categories