Integrate multivariate python function with one positional argument - python

suppose I define a function of an unpackable array (e.g. list)
def f(params):
a,b,c = params
return a+b**2+c**2
is there a way to integrate over only the first parameter? I tried
import scipy.integrate.quad as quad
def integrate(b,c):
return quad(f,0,1,args=(b,c))
but it returns an error because the function f only takes one positional argument. I guess I have to unpack it in the integration step, but unsure how.
Thanks!

If these are the only two use cases for using this function you can do something like the following:
def f(*args):
if len(args) == 1:
a,b,c = args[0]
else:
a, b,c = args
return a+b**2+c**2
This assumes that if you pass one argument to the function in can be unpacked and if you pass more than one you pass a, b, c directly.
In a more generic setting, you can define different behavior of a function depending on the input type using functools.singledispatch. In this case this would look as follows:
from functools import singledispatch
#singledispatch
def f(arg1, arg2=None, arg3=None):
a, b, c = arg1
return a+b**2+c**2
#f.register(int)
#f.register(float)
def _(arg1, arg2, arg3):
return arg1+arg2**2+arg3**2
The advantage of this would be that you can extend it for different input types if that is needed.

Related

Higher order function fixes parameters. Make it fix two parameters as equal

Mock version of the problem
For a function
def f(a,b,c):
return a+b+c
The function
def fix(func, **kwargs):
fa = kwargs.get('a')
fb = kwargs.get('b')
if fa is not None and fb is not None:
def f(*args):
return func(a=fa, b=fb, c=args[0])
elif fa is not None:
def f(*args):
return func(a=fa, b=args[0], c=args[1])
elif fb is not None:
def f(*args):
return func(a=args[0],b=fb, c=args[1])
else:
def f(*args):
return func(args)
return f
allows to obtain a new function by fixing some of the parameters of func.
For example: fix(g, b=3) would give us a function like
def fixed_b_in_g(a,c):
return g(a,3,c)
Question: I would like to see if there is some trick to use fix in such a way that produces a function like
def fix_a_equal_b_in_g(a,c):
return g(a,a,c)
Concrete problem
The function scipy.stats.rv_continuous.fit allows to fit parameters of a distribution to an input sample. It allows to input some keyword arguments (like fix above does) to tell it to keep some of the parameters fixed to values that the user inputs. Internally scipy.stats.rv_continuous.fit has a function, scipy.stats.rv_continuous._reduce_func, that does more or less what dix does (better implemented than my fix for example).
In my case, rather than fixing some parameters to values, I would like to fit to keep two parameters (say a and b) equal to each other, but still free during the fitting.
We can use this function to copy a keyword argument whose name is base_kwarg_name to added_kwarg_name:
def with_copied_kwargs(func, added_kwarg_names_by_base):
def fixed_func(*args, **base_kwargs):
added_kwargs = {
added_kwarg_name: base_kwargs[base_kwarg_name]
for base_kwarg_name, added_kwarg_name in added_kwarg_names_by_base.items()
}
return func(*args, **base_kwargs, **added_kwargs)
return fixed_func
Given:
def add(*, a, b, c):
return a + b + c
then modified_add = with_copied_kwargs(add, {"b": "c"}) is equivalent to:
def modified_add(*, a, b):
return add(a=a, b=b, c=b)
with_copied_kwargs can then be used along with functools.partial to both both copy keyword arguments and provide values incrementally. modified_add = functools.partial(with_copied_kwargs(add, {"b": "c"}), a=1) is equivalent to:
def modified_add(*, b):
return add(a=1, b=b, c=b)
Note that I add * (see PEP 3102) before all parameters in functions I then apply with_copied_kwargs to because the minute people start using positional arguments, things would get messy. So better to restrict it to keyword-only arguments.

python get parameters of passed function

I want to pass a function, f(a=1,b=2) into g and use the 'a' value in g
def f(a,b): pass
def g(f): #print f.a
g(f(1,2)) should result in an output of 1
I looked into the inspect module but can't seem to get hold of f in g
This is as far as my programming knowledge has got me :
def g(f):
print(list(inspect.signature(f).parameters.keys()))
g(f(1,2)) results in: TypeError: None is not a callable object
This is not possible. When you call g(f(1,2)), f(1,2) is finished before g runs. The only way this would be possible would be for f to return its arguments.
You need to call g appropriately, so the f, as a function, is an argument:
g(f, 1, 2)
Now work that into your function:
def g(f, *args):
print(list(inspect.signature(f).parameters.keys()))
... and from here, you can iterate through args to make the proper call to f.
Does that get you moving?
You could do something like this:
def f(a, b):
print(a)
print(b)
Then define wrapper as:
def wrapper(func, a, b):
func(a, b)
Or if you want more flexibility use *args:
def wrapper(func, *args):
func(*args)
That flexibility comes with some risk if the number of arguments don't match. Which means you'll need to take care that all func passed to wrapper have a consistent signature.
You could use **kwargs which would help with the above, then:
def wrapper(func, **kwargs):
func(**kwargs)
Then calls to wrapper would look like:
wrapper(f, a=1, b=2)
This would allow for more flexibility and signature of func could vary as needed.
You could turn wrapper into a decorator but that's another question.

Get function arguments value by pointer to this function?

I'd like to get value of function arguments by pointer to that function.
def cons(a, b):
def pair(f):
return f(a, b)
return pair
def car(cons):
# local_a = cons.a
# return local_a
pass
if __name__ == '__main__':
assert car(cons(3, 4)) == 3
You're on the wrong track. Looking at the code in the new version of your question, you're trying to extract the first element of a Church pair.
cons(3, 4) evaluates to a function that, when passed another function f, returns f(3, 4). To extract the 3, you should pass it a function that takes two arguments and returns its first argument:
def car(pair):
def firstarg(x, y):
return x
return pair(firstarg)
Then car(cons(3, 4)) calls cons(3, 4)(firstarg), which calls firstarg(3, 4), which returns 3.
Creating a Signature for the function is easy via the signature function:
from inspect import signature
def someMethod(self, arg1, kwarg1=None):
pass
sig = signature(someMethod)
Now, you can either view its parameters quickly by string it:
str(sig) # returns: '(self, arg1, kwarg1=None)'
or you can also get a mapping of attribute names to parameter objects via sig.parameters.
params = sig.parameters
print(params['kwarg1']) # prints: kwarg1=20
Additionally, you can call len on sig.parameters to also see the number of arguments this function requires:
print(len(params)) # 3
Each entry in the params mapping is actually a Parameter object that has further attributes making your life easier. For example, grabbing a parameter and viewing its default value is now easily performed with:
kwarg1 = params['kwarg1']
kwarg1.default # returns: None
similarly for the rest of the objects contained in parameters.

How to pass function as variable with fixed argument

I'm newbie in Python, but the second time I encouter this problem.
Problem:
In some libraries there are functions with arguments. Sometimes there is argument as function, like this:
def somefun(fun):
x = [1,2,3]
z = fun(x)
return z
And I want to pass there some other function like this:
def func(x,y):
return x*y
which have more than one argument. I want to make one argument static, so somefun except func as argument.
Finally I want to make some kind of cycle where I can change static arg.
Something like this:
for i in xrange(1,9):
somefun(func(i,*))
Please do not offer me to change any functions. They are from library and it's not very comfortable to change them.
Thanks a lot!
You can use lambda statement:
somefun(lambda x: func(i, x))
It sure sounds like you are looking for functools.partial. From the docs:
functools.partial(func, *args, **keywords)
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords.
In your example, you could pass partial(func, 10) as the argument to somefun. Or you could create the partial objects and use them in a loop:
for i in xrange(1,9):
somefun(partial(func, i))
My solution with decorator
from functools import wraps
import numpy as np
def p_decorate(f):
#wraps(f)
def wrapped(*args):
z = f(*args)
return z
return wrapped
#p_decorate
def myfunc(a,b):
"""My new function"""
z = np.dot(a,b)
return z
x = [1,2,3]
y = [4,2,0]
r = myfunc(x,y)
print (r)
print (myfunc.__name__)
print (myfunc.__doc__)
You can change myfunc as you wish.You can also insert more function layers.Without the use of this decorator factory,you would lose the name of myfunc and the docstring.

Remove function argument after setting it to a value with functools.partial

I would like to use functools.partial to set a certain argument to a constant and at the same time remove the argument altogether.
Let me explain it using a simple example.
from functools import partial
def f(a, b):
return a * b
g = partial(f, b=2)
However, this function g still has the following calling signature:
g?
Signature: g(a, *, b=1)
Call signature: g(*args, **kwargs)
Type: partial
String form: functools.partial(<function f at 0x7ff7045289d8>, b=1)
File: /opt/conda/envs/dev/lib/python3.6/functools.py
Docstring:
partial(func, *args, **keywords) - new function with partial application
of the given arguments and keywords.
I could of course do this with a lambda function like:
def f(a, b):
return a * b
g = lambda a: f(a, b=2)
with the correct calling signature:
g?
Signature: g(a)
Docstring: <no docstring>
File: ~/Work/<ipython-input-7-fc5f3f492590>
Type: function
The downside of using lamdba functions is that I would need to write down all the arguments again. In my simple example this doesn't matter, but look at this:
phase_func = lambda site1, site2, B_x, B_y, B_z, orbital, e, hbar: \
phase_func(site1, site2, B_x, B_y, B_z, orbital, e, hbar, xyz_offset=(0,0,0))
# or this
phase_func = partial(phase_func, xyz_offset=(0,0,0)
Why would I even want this?
Later in my code I use wrappers that can generate a new function by multiplying two other functions, like combine(function1, function2, operator.mul). This combine function looks at all the arguments, therefore I need to remove the argument after setting it.

Categories

Resources