I searched about it and got the following, python obtain variable name of argument in a function but i am not getting required answer and am actually getting an error saying add () takes exactly 0 arguments when i used kwargs. So reposted to get an answer if there is any.
i have the following code,
def add ( arg1, arg2):
z = arg1 + arg2
print arg1Name, arg2Name, z
x = 10
y = 5
add( x,y )
i want output as
x y 15
You should use func_code.co_varnames attribute of your function to access parameters names:
def add(arg1, arg2):
z = arg1 + arg2
print ' '.join(add.func_code.co_varnames[:2]) + ' ' + str(z)
add(10, 5)
Output:
arg1 arg2 15
You can read more about internal attributes here:
https://docs.python.org/2/library/inspect.html#types-and-members
I think the closest you can get to what you want is as follows:
def add (**kwargs):
assert len(kwargs) == 2, "Not enough arguments"
keys = kwargs.keys()
z = kwargs[keys[0]] + kwargs[keys[1]]
print keys[0], keys[1], z
x = 10
y = 5
add(x=x,y=y)
add(w=11,t=11)
Results in:
y x 15
t w 22
One liner solution here,**kwargs returns a dict, check that with;
def add(**kwargs):
print (kwargs)
add(x=5,y=10)
>>>
{'y': 10, 'x': 5}
>>>
It's a normal dict. You can reach the each element with basic dict methods.
print (kwargs.keys())
>>>
dict_keys(['y', 'x'])
>>>
Using kwargs is a tradition actually, you can use whatever you want instead of it. Here is the solution,print dict keys and sum of values;
def add(**ChuckNorris): #instead of **kwargs
print (" ".join(ChuckNorris.keys()),sum(list(ChuckNorris.values())))
add(x=5,y=10)
>>>
x y 15
>>>
You can do it using the traceback module.
def get_current_arg_names():
import traceback, re
tb = traceback.extract_stack()
method = tb[-2][2]
func_call = tb[-3][3]
args = re.search('%s\s*\((.*?)\)' % method, func_call).group(1)
return [ x.strip() for x in args.split(',') ]
def add(arg1, arg2):
z = arg1 + arg2
print get_current_arg_names(), z
return z
x = 1
y = 3
print add(x, y)
However the regex would need to be improved and event then, there is a requirement that the function call not be spread across multiple lines.
Better to modify you code if possible as this is messy.
Related
Is it possible for one function to take as an argument the name of one of the optional arguments of a second function then call the second function with the optional argument set to the value of some variable in the first function?
Code (that obviously doesn't work)
def foo(a=1,b=2,c=3):
d = a + b + c
return d
def bar(variable):
z = get_user_input()
e = foo(variable = z)
return e
print(bar(a))
The desired result is for bar to call foo(a=z) and print whatever z+2+3 is. Of course Python doesn't know what (a) is here. My guess is that I can somehow reference the list of arguments of foo() , but I am stumped as to how you might do that.
Maybe try the code snippet below
def foo(a=1,b=2,c=3):
d = a + b + c
return d
def bar(variable: str):
z = int(input())
e = foo(**{variable: z})
return e
# variable name should be defined as string
print(bar("a"))
The ** parses all arbitrary arguments on dict, in this case is a. Be careful tho, as if passing wrong variable name (differ from a, b or c) will result raising error.
Given a simple function:
def A(a = 1, b = 2):
return a+b
I want to write another function to change the default parameter value, for either a or b. And user can specify the parameter to change by setting var = a or var = b. For example:
def B(var = 'a', new_value = 10):
temp_dict = {var:new_value}
ans = A(var)
return ans
or
def B(var = 'a', new_value = 10):
ans = A(var = new_value)
return ans
In function def B(), after setting var = a and var = new_value = 10, I expect A(var = new_value) to achieve the same effect as A(a = 10). Do you know the correct way to write function def B()?
Thanks.
You are almost there. From your B() function, while making the call to A(), you need to unpack the temp_dict and pass it as an argument to A(). See below:
>>> def A(a = 1, b = 2):
... return a+b
...
>>> def B(var = 'a', new_value = 10):
... temp_dict = {var:new_value}
... ans = A(**temp_dict)
# ^ unpack the dict, and pass it as an argument
... return ans
...
>>> B()
12
For more details on how this ** works with a dict, please take a look at:
Python: *args and **kwargs?
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
I took the liberty of interpreting a bit what the OP said he wanted, i.e. change the default parameter value, for either a or b. So what I did was to return a transformed function A with either the a or b defaults changed via a partial:
from functools import partial
def B3(var ="a", new_value=10):
return partial(A, **{var:new_value})
sample outputs:
(Pdb) f = B3("a",10)
(Pdb) f()
12
(Pdb) f = B3("b",10)
(Pdb) f()
11
(Pdb) f(a=10)
20
(Pdb) f(b=13)
14
(Pdb) f(a=5,b=5)
10
That is different from the 2nd half of the request however, that of having something based on B(var="a",new_value=10) as function signature.
The only thing is, it chokes happily if you don't use keyword parameters:
(Pdb) f(7,7)
*** TypeError: A() got multiple values for keyword argument 'b'
Defaults are parsed at definition. So this will not work
def f(x, func = f):
if x<1:
return x
else:
return x + func(x-1)
I did find a way, though. I start with some dummy function
def a(x):
return x
def f(x, func=a):
if x < 1:
return x
else:
return x + func(x-1)
And then issue
f.__defaults__ = (f,)
Obviously awkward. Is there another way or is this bad python? If it's bad, can you explain why? Where will it break things?
In any case, it works:
In [99]: f(10)
Out[99]: 55
In [100]: f(10, f)
Out[100]: 55
In [101]: f(10, lambda x : 2*x)
Out[101]: 28
To elaborate on Andrea Corbellini's suggestion, you can do something like this:
def f(x, func=None):
if func is None:
func = f
if x < 1:
return x
else:
return x + func(x-1)
It is a pretty standard idiom in Python to implement the actual defaults inside of the function and defining the default parameter as None (or some private sentinel object in case None is valid input), due to problems with mutable default values such as list objects.
So this works:
>>> x = 1
>>> y = 2
>>> "a={a}, b={b}, a+b={c}".format( a=x, b=y, c=x+y )
'a=1, b=2, a+b=3'
But this doesn't:
>>> "a={a}, b={b}, a+b={c}".format( a=x, b=y, c=a+b )
NameError: name 'a' is not defined
Is there any way to make the second one work? (Say for example that x and y are function calls and I don't want to recompute them during string formatting)
The most pythonic (readable, in this case) solution for this is not to use a lambda function, but to cache a and b before the format() call:
a = function_x()
b = function_y()
"a={a}, b={b}, a+b={c}".format(a=a, b=b, c=a+b)
You'll be thankful when looking at the code 6 months from now.
You can do it with lambda:
def x():
return 1
def y():
return 2
>>> "a={a},b={b}, a+b={c}".format(**(lambda a=x(),b=y():{'a':a,'b':b,'c':a+b})())
'a=1,b=2, a+b=3'
this lambda expression is equal to calling predefined function:
def twosumm(a, b):
return {'a':a, 'b':b, 'c': a+b}
>>> "a={a},b={b}, a+b={c}".format(**twosumm(x(), y()))
'a=1,b=2, a+b=3'
Im also think that it is better to use simple and readable solution and just call x() and y() to get results before formatiing:
>>> a, b = x(), y()
>>> "a={a},b={b}, a+b={c}".format(a=a, b=b, c=a+b)
'a=1,b=2, a+b=3'
x = 1
y = 2
def f(x,y):
return (x,y,x+y)
print "a={}, b={}, a+b={}".format( *f(x,y) )
# or
print "a={0[0]}, b={0[1]}, a+b={0[2]}".format( f(x,y) )
.
EDIT
I think your question is wrongly written and that induces blurry understanding of it, and then wrong answers.
x and y are not function calls. As they appear, they are just identifiers
If you evoke function calls, I think it is because, in fact, you wish to obtain the result of something like that:
"a={a}, b={b}, a+b={c}".format( a=f(), b=g(), c=f()+g() )
but without having to write c=f()+g() because it implies that f() and g() are each executed two times.
Firstly, it will forever be impossible in Python to write something like .format( a=x, b=y, c=a+b ) or .format( a=f(), b=g(), c=a+b ) where a and b in c=a+b will refer to the same objects as a and b in a=x and b=y.
Because any identifier at the left side of = is in the local namespace of format() while any identifier at the right side of = is in the namespace outside of the function format().
By the way, that's why the identifiers at the left are called parameters and the identifiers at the right are the identifiers of objects passed as arguments.
Secondly, if you want to avoid writing f() two times (one time as an alone argument and one time in the expression f()+g()), and the same for g(), that means you want to write each only one time, as alone argument.
So , if I understand you well, you essentially wish to write something like that:
"a={a}, b={b}, a+b={}".format( a=f(), b=g() )
With current method str.format , this expression with three replacement fields { } is evidently not correct.
No matter, let's redefine the method format ! And then it's possible to pass only two arguments to format().
def fx(): return 101
def fy(): return 45
class Pat(str):
def __init__(self,s):
self = s
def format(self,x,y):
return str.format(self,x,y,x+y)
p = Pat("a={}, b={}, a+b={}")
print 'p==',p
print p.format(fx(),fy())
result
p : a={}, b={}, a+b={}
a=101, b=45, a+b=146
We can even do more complex things:
from sys import exit
import re
def fx(): return 333
def fy(): return 6
class Pat(str):
def __init__(self,s):
for x in re.findall('(?<=\{)[^}]+(?=\})',s):
if x not in ('A','M'):
mess = " The replacement field {%s] isn't recognised" % x
exit(mess)
self.orig = s
self.mod = re.sub('\{[^}]*\}','{}',s)
def modif(self,R):
it = iter(R)
return tuple(sum(R) if x=='{A}'
else reduce(lambda a,b: a*b, R) if x=='{M}'
else next(it)
for x in re.findall('(\{[^}]*\})',self))
def format(self,*args):
return ''.join(self.mod.format(*self.modif(args)))
print Pat("a={}, b={}, a+b={A}").format(fx(),fy())
print '******************************************'
print Pat("a={}, b={}, c={}, a+b+c={A}").format(fx(),fy(),5000)
print '******************************************'
print Pat("a={}, b={}, a*b={M}").format(fx(),fy())
print '******************************************'
print Pat("a={}, b={}, axb={X}").format(fx(),fy())
result
a=333, b=6, a+b=339
******************************************
a=333, b=6, c=5000, a+b+c=5339
******************************************
a=333, b=6, a*b=1998
******************************************
Traceback (most recent call last):
File "I:\potoh\ProvPy\Copie de nb.py", line 70, in <module>
print Pat("a={}, b={}, axb={X}").format(fx(),fy())
File "I:\potoh\ProvPy\Copie de nb.py", line 51, in __init__
exit(mess)
SystemExit: The replacement field {X] isn't recognised
This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 9 years ago.
Does * have a special meaning in Python as it does in C? I saw a function like this in the Python Cookbook:
def get(self, *a, **kw)
Would you please explain it to me or point out where I can find an answer (Google interprets the * as wild card character and thus I cannot find a satisfactory answer).
See Function Definitions in the Language Reference.
If the form *identifier is
present, it is initialized to a tuple
receiving any excess positional
parameters, defaulting to the empty
tuple. If the form **identifier is
present, it is initialized to a new
dictionary receiving any excess
keyword arguments, defaulting to a new
empty dictionary.
Also, see Function Calls.
Assuming that one knows what positional and keyword arguments are, here are some examples:
Example 1:
# Excess keyword argument (python 2) example:
def foo(a, b, c, **args):
print "a = %s" % (a,)
print "b = %s" % (b,)
print "c = %s" % (c,)
print args
foo(a="testa", d="excess", c="testc", b="testb", k="another_excess")
As you can see in the above example, we only have parameters a, b, c in the signature of the foo function. Since d and k are not present, they are put into the args dictionary. The output of the program is:
a = testa
b = testb
c = testc
{'k': 'another_excess', 'd': 'excess'}
Example 2:
# Excess positional argument (python 2) example:
def foo(a, b, c, *args):
print "a = %s" % (a,)
print "b = %s" % (b,)
print "c = %s" % (c,)
print args
foo("testa", "testb", "testc", "excess", "another_excess")
Here, since we're testing positional arguments, the excess ones have to be on the end, and *args packs them into a tuple, so the output of this program is:
a = testa
b = testb
c = testc
('excess', 'another_excess')
You can also unpack a dictionary or a tuple into arguments of a function:
def foo(a,b,c,**args):
print "a=%s" % (a,)
print "b=%s" % (b,)
print "c=%s" % (c,)
print "args=%s" % (args,)
argdict = dict(a="testa", b="testb", c="testc", excessarg="string")
foo(**argdict)
Prints:
a=testa
b=testb
c=testc
args={'excessarg': 'string'}
And
def foo(a,b,c,*args):
print "a=%s" % (a,)
print "b=%s" % (b,)
print "c=%s" % (c,)
print "args=%s" % (args,)
argtuple = ("testa","testb","testc","excess")
foo(*argtuple)
Prints:
a=testa
b=testb
c=testc
args=('excess',)
I only have one thing to add that wasn't clear from the other answers (for completeness's sake).
You may also use the stars when calling the function. For example, say you have code like this:
>>> def foo(*args):
... print(args)
...
>>> l = [1,2,3,4,5]
You can pass the list l into foo like so...
>>> foo(*l)
(1, 2, 3, 4, 5)
You can do the same for dictionaries...
>>> def foo(**argd):
... print(argd)
...
>>> d = {'a' : 'b', 'c' : 'd'}
>>> foo(**d)
{'a': 'b', 'c': 'd'}
All of the above answers were perfectly clear and complete, but just for the record I'd like to confirm that the meaning of * and ** in python has absolutely no similarity with the meaning of similar-looking operators in C.
They are called the argument-unpacking and keyword-argument-unpacking operators.
A single star means that the variable 'a' will be a tuple of extra parameters that were supplied to the function. The double star means the variable 'kw' will be a variable-size dictionary of extra parameters that were supplied with keywords.
Although the actual behavior is spec'd out, it still sometimes can be very non-intuitive. Writing some sample functions and calling them with various parameter styles may help you understand what is allowed and what the results are.
def f0(a)
def f1(*a)
def f2(**a)
def f3(*a, **b)
etc...
I find * useful when writing a function that takes another callback function as a parameter:
def some_function(parm1, parm2, callback, *callback_args):
a = 1
b = 2
...
callback(a, b, *callback_args)
...
That way, callers can pass in arbitrary extra parameters that will be passed through to their callback function. The nice thing is that the callback function can use normal function parameters. That is, it doesn't need to use the * syntax at all. Here's an example:
def my_callback_function(a, b, x, y, z):
...
x = 5
y = 6
z = 7
some_function('parm1', 'parm2', my_callback_function, x, y, z)
Of course, closures provide another way of doing the same thing without requiring you to pass x, y, and z through some_function() and into my_callback_function().