How to get method parameter names?

213,911

Solution 1

Take a look at the inspect module - this will do the inspection of the various code object properties for you.

>>> inspect.getfullargspec(a_method)
(['arg1', 'arg2'], None, None, None)

The other results are the name of the *args and **kwargs variables, and the defaults provided. ie.

>>> def foo(a, b, c=4, *arglist, **keywords): pass
>>> inspect.getfullargspec(foo)
(['a', 'b', 'c'], 'arglist', 'keywords', (4,))

Note that some callables may not be introspectable in certain implementations of Python. For Example, in CPython, some built-in functions defined in C provide no metadata about their arguments. As a result, you will get a ValueError if you use inspect.getfullargspec() on a built-in function.

Since Python 3.3, you can use inspect.signature() to see the call signature of a callable object:

>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>

Solution 2

In CPython, the number of arguments is

a_method.func_code.co_argcount

and their names are in the beginning of

a_method.func_code.co_varnames

These are implementation details of CPython, so this probably does not work in other implementations of Python, such as IronPython and Jython.

One portable way to admit "pass-through" arguments is to define your function with the signature func(*args, **kwargs). This is used a lot in e.g. matplotlib, where the outer API layer passes lots of keyword arguments to the lower-level API.

Solution 3

The Python 3 version is:

def _get_args_dict(fn, args, kwargs):
    args_names = fn.__code__.co_varnames[:fn.__code__.co_argcount]
    return {**dict(zip(args_names, args)), **kwargs}

The method returns a dictionary containing both args and kwargs.

Solution 4

In a decorator method, you can list arguments of the original method in this way:

import inspect, itertools 

def my_decorator():

        def decorator(f):

            def wrapper(*args, **kwargs):

                # if you want arguments names as a list:
                args_name = inspect.getargspec(f)[0]
                print(args_name)

                # if you want names and values as a dictionary:
                args_dict = dict(itertools.izip(args_name, args))
                print(args_dict)

                # if you want values as a list:
                args_values = args_dict.values()
                print(args_values)

If the **kwargs are important for you, then it will be a bit complicated:

        def wrapper(*args, **kwargs):

            args_name = list(OrderedDict.fromkeys(inspect.getargspec(f)[0] + kwargs.keys()))
            args_dict = OrderedDict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems()))
            args_values = args_dict.values()

Example:

@my_decorator()
def my_function(x, y, z=3):
    pass


my_function(1, y=2, z=3, w=0)
# prints:
# ['x', 'y', 'z', 'w']
# {'y': 2, 'x': 1, 'z': 3, 'w': 0}
# [1, 2, 3, 0]

Solution 5

I think what you're looking for is the locals method -


In [6]: def test(a, b):print locals()
   ...: 

In [7]: test(1,2)              
{'a': 1, 'b': 2}
Share:
213,911

Related videos on Youtube

Staale
Author by

Staale

Java and Python programmer dealing in web solutions.

Updated on March 22, 2022

Comments

  • Staale
    Staale over 2 years

    Given the Python function:

    def a_method(arg1, arg2):
        pass
    

    How can I extract the number and names of the arguments. I.e., given that I have a reference to func, I want the func.[something] to return ("arg1", "arg2").

    The usage scenario for this is that I have a decorator, and I wish to use the method arguments in the same order that they appear for the actual function as a key. I.e., how would the decorator look that printed "a,b" when I call a_method("a", "b")?

    • Nick
      Nick over 13 years
      For a different list of answers to a nearly identical question, see this other stackoverflow post
    • Juh_
      Juh_ almost 12 years
      Your title is misleading: when one say 'method' w.r.t the word 'function', one usually think of a class method. For function, your selected answer (from Jouni K. Seppanen) is good. But for (class) method, it is not working and the inspect solution (from Brian) should be used.
  • MattK
    MattK over 13 years
    co_varnames does work with standard Python, but this method is not preferable since it will also display the internal arguments.
  • hochl
    hochl over 13 years
    Why not use aMethod.func_code.co_varnames[:aMethod.func_code.co_argcount‌​]?
  • Piotr Dobrogost
    Piotr Dobrogost over 12 years
    This is useless outside of a function which is the context of interest here (decorator).
  • Andre Holzner
    Andre Holzner over 11 years
    see also stackoverflow.com/a/3999574/288875 on examining callables in general
  • fatuhoku
    fatuhoku almost 11 years
    How could the code possibly know that the default parameter (4,) corresponds to the keyword parameter c specifically?
  • Soverman
    Soverman over 10 years
    @fatuhoku I was wondering the same thing. Turns out it's not ambiguous since you can only add default arguments at the end in a contiguous block. From the docs: "if this tuple has n elements, they correspond to the last n elements listed in args"
  • javabeangrinder
    javabeangrinder almost 9 years
    Actually exactly what I was looking for although it is not the answer to the question here.
  • Diego Andrés Díaz Espinoza
    Diego Andrés Díaz Espinoza almost 8 years
    I think since Python 3.x getargspec(...) is replaced by inspector.signature(func)
  • Charlie Parker
    Charlie Parker almost 8 years
    Just emphasize the fact that this doesn't work with built in since I recently discovered that if the function is in C it seems it won't work for some reason, see: stackoverflow.com/questions/39194325/….
  • theannouncer
    theannouncer over 7 years
    Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs, keywords, defaults).
  • Peter Majko
    Peter Majko almost 7 years
    dir() returns list of all variable names ['var1', 'var2'], vars() returns dictionary in form {'var1': 0, 'var2': 'something'} from within the current local scope. If someone wants to use argument variables names later in the function, they should save in another local variable, because calling it later in the function where they could declare another local variables will "contaminate" this list. In the case they want to use it outside of the function, they must run function at least once and save it in global variable. So it's better to use inspect module.
  • j08lue
    j08lue over 6 years
    That is right, @DiegoAndrésDíazEspinoza - in Python 3, inspect.getargspec is deprecated, but the replacement is inspect.getfullargspec.
  • Hendrik Wiese
    Hendrik Wiese almost 6 years
    It's probably frowned upon here but as a German I cannot resist, sorry about that, but I somehow like the parameter name 'arglist'.
  • Blairg23
    Blairg23 over 5 years
    >>> inspect.getargspec(api_function) ./manage.py:1: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() or inspect.getfullargspec() #!/usr/bin/env python3
  • Matthew D. Scholefield
    Matthew D. Scholefield over 5 years
    You can now do inspect.signature(api_function).bind(*args).parameters as mentioned in this answer: stackoverflow.com/a/45781963/2132312
  • Soren Bjornstad
    Soren Bjornstad about 5 years
    Notice that the [:fn.__code__.co_argcount] is very important if you're looking for the function arguments -- otherwise it includes names created within the function as well.
  • Nikolay Makhalin
    Nikolay Makhalin almost 5 years
    Not working with arguments after *args, e.g.: def foo(x, *args, y, **kwargs): # foo.__code__.co_argcount == 1
  • Kiann
    Kiann over 4 years
    what if we would like to get the list of possible values for each argument? Is there a way?
  • Brian McCutchon
    Brian McCutchon over 4 years
  • Brian McCutchon
    Brian McCutchon over 4 years
    Please use inspect instead. Otherwise, your code doesn't work well with functools.wraps in 3.4+. See stackoverflow.com/questions/147816/…
  • Imago
    Imago over 4 years
    This answer is partially obsolete and should be updated.
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com almost 4 years
    One problem with this is that it does not show if an argument is *args or **kwargs.
  • Dmytro Bugayev
    Dmytro Bugayev about 3 years
    neat solution. Would be even nicer if could be generalised for instance and class methods, for which the offset needs to start at 1 to skip over the self/cls arg
  • Michał Jabłoński
    Michał Jabłoński over 2 years
    If you only want a param list, then list(inspect.signature(function).parameters) is enough, you don't need to call the .keys() method. Anyway, this is a great answer.
  • Nicholas Jela
    Nicholas Jela over 2 years
    this code even can not be run
  • Dust break
    Dust break about 2 years
    which one is better? fn.__code__.co_varnames[:fn.__code__.co_argcount] or inspect.getargspec(f)[0]
  • Thingamabobs
    Thingamabobs about 2 years
    co_argcount includes keywords, so f_code.co_kwonlyargcount is not needed.