I have a function that takes 3 keyword parameters. It has default values for x and y and I would like to call the function for different values of z using map. When I run the code below I get the following error:
foo() got multiple values for keyword argument 'x'
def foo(x =1, y = 2, z = 3):
print 'x:%d, y:%d, z:%d'%(x, y, z)
if __name__ == '__main__':
f1 = functools.partial(foo, x= 0, y = -6)
zz = range(10)
res = map(f1, zz)
Is there a Pythonic way to solve this problem?
map(f1, zz) tries to call the function f1 on every element in zz, but it doesn't know with which arguments to do it. partial redefined foo with x=0 but map will try to reassign x because it uses positional arguments.
To counter this you can either use a simple list comprehension as in #mic4ael's answer, or define a lambda inside the map:
res = map(lambda z: f1(z=z), zz)
Another solution would be to change the order of the arguments in the function's signature:
def foo(z=3, x=1, y=2):
You may obtain the equivalent result you expect without using partial:
def foo(x =1, y = 2, z = 3):
print 'x:%d, y:%d, z:%d'%(x, y, z)
if __name__ == '__main__':
f1 = lambda z: foo(x=0, y=-6, z=z)
zz = range(10)
res = map(f1, zz)
Please see this link to have a better understanding: functools.partial wants to use a positional argument as a keyword argument
When trying to call res = map(f1, zz) internally it actually looks like [f1(i) for i in range(10). As you can see you call f1 function with only one positional argument (in this case f1(x=i)). A possible solution would be to do something like this
res = [f1(z=i) for i in range(10)]
Related
I am trying to integrate over some function with vegas library, a simple implement that integrates f(x) = lambda x: x ** 2.0 is
import vegas
f = lambda x: x ** 2.0
integrator = vegas.Integrator([[0.0, 1.0]])
result = integrator(f, nitn = 10, neval = 10000)
print result
which would print [0.33333389(69)] and is correct. However, if I would like to be able to change the power value of function f but adding an input parameter like the following
def f(x, p):
return x ** p
The method Integrator would complain the following
SyntaxError: invalid syntax
Using global variable to pass p would mess up the code because in practice, I have a lot of parameter to pass onto f. Using the following alternative definition would involve changing the actual definition of the function and is not a preferred solution
def f(x, p = 2.0):
return x ** p
So what could I do to pass parameter to f which is called in method Integrator? Thanks in advance!
One solution is to have a function that will build your power function:
def to_the_power(p):
return lambda x: x ** p
result = integrator(to_the_power(2), nitn = 10, neval = 10000)
That technique is usually referred as currying, here we curry the power function so we can pass parameters one by one instead of all at once. Note that if you need to do this with several parameters or if you use a function you don't have control over, you may find functools.partial useful:
import functools
def f(p, x):
return x ** p
integrator(functools.partial(f, 2), nitn = 10, neval = 10000)
Suppose I have the following function
def f(x,y,**kwargs):
if 'z' in kwargs:
z = kwargs['z']
else:
z = 0
print(x + y + z)
which takes two arguments and an optional keyword argument. I now want to get a function g that works just as f but for which the value of z is predetermined. Hence, I could do the following
def g(x,y):
z = 3
f(x,y, z = 3)
But what can I do if I do not know the number of non-keyword arguments that f takes. I can get the list of these arguments by
args = inspect.getargspec(f)[0]
But, if I now define g as
g(args):
z = 3
f(args, z=z)
this of course does not work as only one mandatory argument is passed to f. How do I get around this? That is, if I have a function that takes keyword arguments, how do I define a second function exactly the same expect that the keyword arguments take predeterminde values?
You have a few options here:
Define g with varargs:
def g(*args):
return f(*args, z=3)
Or, if you need keyword arguments as well:
def g(*args, **kwargs):
kwargs['z'] = 3
return f(*args, **kwargs)
Use functools.partial:
import functools
g = functools.partial(f, z=3)
See also this related question: Python Argument Binders.
You can use functools.partial to achieve this
import functools
f = functools.partial(f, z=2)
# the following example is the usage of partial function f
x = f(1, 2)
y = f(1, 2, k=3)
z = f(1, 2, z=4)
I have a function that most of the time should return a single value, but sometimes I need a second value returned from the function. Here I found how to return multiple values, but as most of the time I need only one of them I would like to write something like this:
def test_fun():
return 1,2
def test_call():
x = test_fun()
print x
but calling this results in
>>> test_call()
(1,2)
and when trying to return more than two, as in
def test_fun2():
return 1,2,3
def test_call2():
x,y = test_fun2()
print x,y
I get an error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "my_module.py", line 47, in test_call2
x,y = test_fun2()
ValueError: too many values to unpack
I am thinking about something like in matlab, where x = test_fun() would result in x == 1 (while [x y] = test_fun() would also work as expected). Is something like that possible in python?
You can use star unpacking to gather all additional return values into a list:
x, *y = fun()
x will contain the first return value. y will be a list of the remaining values. y will be empty if there is only one return value. This particular example will only work if the function returns a tuple, even if there is only one value.
When fun always returns 1 or 2 values, you can just do
if y:
print(y[0])
else:
print('only one value')
If, on the other hand, you want to completely ignore the number of return values, do
*x = fun()
Now all the arguments will be gathered into the list. You can then print it with either
print(x)
or
print(*x)
The latter will pass each element as a separate argument, exactly as if you did
x, y, z = fun()
print(x, y, z)
The reason to use *x = fun() instead of just x = fun() is to get an error immediately when a function returns something that isn't a tuple. Think of it as an assertion to remind you to write fun properly.
Since this form of star unpacking only works in Python 3, your only option in Python 2 is to do
x = fun()
and to inspect the result manually.
There are several ways to get multiple return values.
Example 1:
def test_fun():
return 1,2
def test_call():
x, y = test_fun()
print x
print y
you will get correct output:
1
2
When you would like to ignore several return values, you can use * before a variable in python3.
Example 2:
def test_fun2():
return 1,2,3
def test_call2():
x, *y = test_fun2()
print x
print y
you will get the result:
1
(2, 3)
I have just started to study Python and I am now in the process of doing some exercises.
Specifically, this exercise asks to write a Python program to sum three given integers. However, if two values are equal sum will be zero.
This is my code:
from sys import argv
script, x, y, z = argv
def sum(x, y, z):
if x == y or y == z or x==z:
sum = 0
else:
sum = x + y + z
return sum
print (sum)
I am opening the script in WindowPowerShell specifying the script name (es3.py) and the three variables, e.g: 1 2 3.
However I get the following message:
<function sum at 0x0000000001E0F048>
instead of the result I was expecting.
Does anyone have any ideas of why this is happening?
Thanks.
Let me comment your code:
script, x, y, z = argv
# we now have four new variables inside the main module:
# script, x, y, z
# all functions defined here have access to these but
# cannot modify them (unless we use "global").
def sum(x, y, z):
# while sum() in principle has access to the
# variables defined outside of sum(),
# sum() (the function) also takes three parameters.
# these need to be passed in with a function call
# (i.e. sum(x, y, z)).
#
# x, y, z here are unrelated to x, y, z outside of sum().
# in fact the parameters shadow the global variables,
# making them inaccessible (via direct means).
if x == y or y == z or x==z:
sum = 0
# this defines a local variable "sum".
# it is unrelated to the function "sum"
else:
sum = x + y + z
# x, y, z are strings, so "sum" is now a string, too.
return sum
print (sum)
# here, you refer to the function "sum".
# the variable "sum" only exists inside the function "sum".
If you want the result of sum() (the function), you need call it with parameters:
print(sum(x, y, z))
You cannot access the variable sum outside of the function.
If you
print(sum)
then you print the function sum.
If you want to print the result, you must call sum:
print(sum(x, y, z))
print (sum(x,y,z))
means call your function/method and print the return value.
print (sum)
means print the meta data of your data(sum is also a type of data)
You should print the result of the sum function :
print(sum(x, y, z))
This way the return value of the sum function will be printed out. The way you did it, just prints out a function reference.
Also as a side note, that sum() is a built-in python function, so it's best to avoid naming conflicts and name your functions accordingly.
Try the following code:
from sys import argv
script, x, y, z = argv
def sum_(x, y, z):
if x == y or y == z or x==z:
the_sum = 0
else:
the_sum = int(x) + int(y) + int(z)
return the_sum
print(sum_(x, y, z))
Is it possible to make a function's keyword argument default defined to a variable name? I want to do this because I'm finding myself creating functions with a lot of keyword arguments, but I'd like these keyword arguments default to a variable name I define before using the function. I'm also open to solutions that allows me to fix the repetitiveness problem in other ways. this was just one idea i was musing about.
for instance, i'd like to do something like this
def do_something(x=x, y=y, z=z, t=t):
return x, y
I know the above returns an error because I haven't defined x yet.
i'm too lazy to constantly write:
x = 100
y= 50
z= 10
t= 1
do_something(x=x, y=y, z=z, t=t)
I'd rather just write with the defaults already assumed as the variable names:
x = 100
y= 50
z= 10
t= 1
do something()
Python lets you pass in a dictionary and tell the function to unpack it
args = dict(x=100, y=50, z=5, t=1)
def do_something(args) # star tells the function to unpack as dict the variables you made
do_something(**args) # call it like this
You can even pass it in as a list with one star:
args = [100, 50, 5, 1]
def do_something(x,y,z,t) # star tells the function to unpack the variables you made
do_something(*args) # call it like this
Python also allows default parameters:
do_something(x=100, y=50, z=5, t=1) #if you don't pass arguments, it will use these defaults
Have you checked the functools module?
from functools import partial
def do_something(x,y,z,t):
print(x,y,z,t)
do_something = partial(do_something, x=100, y=50, z=10, t=1)
do_something()
do_something(x=30)
The easiest way is to use a dictionary instead of variables:
def do_something(x, y, z, t):
...
data = dict(
x = 100,
y = 50,
z = 10,
t = 1
)
do_something(**data)
Here's a really hacky way to do it:
import inspect
def autofill(fn):
def _autofill(*args, **kwargs):
kwargs.update({arg:globals()[arg] for arg in inspect.getargspec(fn).args if arg not in kwargs})
return fn(*args, **kwargs)
return _autofill
>>> #autofill
... def f(x,y):
... return x,y
...
>>> x = 1; y = 20
>>> f()
(1, 20)
>>> f(y=2)
(1, 2)