8

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
Community
  • 1
  • 1
  • 6
    To obtain the exact result you demand is simply **impossible**. By the time `add` start, the names you crave to print are just not there to retrieve. Give up on this and accept alternatives such as the one you quote and misunderstand (requiring a call `add(x=x, y=y)` to actually **preserve** those names you crave so badly -- for whatever misbegotten reason:-) – Alex Martelli Feb 16 '15 at 06:45
  • 2
    To add to what Alex says, moreover, if the function is called as `add(3, 4)` or `add(some_other_func(), a + b)`, then what is the "parameter name"? – Thanatos Feb 16 '15 at 07:04
  • @AlexMartelli Think about how in the case of an error, a traceback is able to show you exactly which source lines up the stack triggered the error. So no, it's not impossible. – tripleee Feb 16 '15 at 07:04
  • @tripleee, I know everything about tracebacks, thanks -- they show **lines of code**, they do **not** show "argument names" which is, indeed, impossible (arguments are expressions evaluated before the function begins executing: one case out of a zillion is when those expressions are just mentions of names, but nothing at runtime is different for that case). The upvoted answer below shows **parameter** names, i.e does not answer the question posed but a completely different one. – Alex Martelli Feb 16 '15 at 15:16
  • Knowing that what you want to do is expensive, you might want to think again about your higher-level problem and devise another way to solve that? – Paddy3118 Feb 16 '15 at 15:31

4 Answers4

7

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

Eugene Soldatov
  • 9,755
  • 2
  • 35
  • 43
4

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
Anshul Goyal
  • 73,278
  • 37
  • 149
  • 186
Marcin
  • 215,873
  • 14
  • 235
  • 294
  • @vks I dont think add.func_code.co_varnames results in `x` and `y` name output. It will just give names of function arguments, i.e. `arg1`, `arg2`, not `x` and `y`. – Marcin Feb 16 '15 at 07:05
  • I also tried and it does not work for me. So if you put `add(x,y)` the function prints `x y 15` even though the arguments are called `arg1` and `arg2`? If so, can you provide version of python which you use and os. Maybe its os/python specific. – Marcin Feb 16 '15 at 07:08
  • Yep, he wants x and y. the name of input arguments. So it was already explained it cant be done. Using dict is the closes you can probably get to it. – Marcin Feb 16 '15 at 07:10
  • He writes "i want output as `x y 15`". Using `add.func_code.co_varnames` gives `arg1 arg2 15`. – Marcin Feb 16 '15 at 07:13
  • @vks So I would recommend making an answer. Its interesting to see alternative solutions to this problem, or the closes one can get. – Marcin Feb 16 '15 at 07:18
2

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
>>> 
GLHF
  • 3,835
  • 10
  • 38
  • 83
1

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.

Tris Forster
  • 152
  • 4