Search code examples
python-3.xfunctionvariablesargsgetattr

Could someone please explain how the function getattr(Object, function) works when passed variables?


So I am working on some hackerrank questions and someone posted the following snippet of code as part of a solution and I was curious if someone could explain it to me please?

getattr(l, parts[0])(*(map(int, parts[1:])))

In the following thread:

Python using getattr to call function with variable parameters

Mgilson mentioned this can be done for any function/method and I became confused.

In the getattr() documentation I found no information of passing *args after the function and so was confused. Is this method generally applicable to all functions? If so could someone please provide a few basic examples and explain why this is true?

I would greatly appreciate this!


Solution

  • You won't find this in getattr's documentation because passing arguments to a function using the * operator is a totally different thing.

    This code:

    l = "my_fun"
    getattr(l, parts[0])(*(map(int, parts[1:])))
    

    is actually equivalent to:

    l = "my_fun"
    fun = getattr(l, parts[0])
    fun(*(map(int, parts[1:])))
    

    You get the function called my_fun, then call this function. map(int, parts[1:]) maps items of parts[1:] to integers and then the * operator unpacks these integer to use them as arguments of fun.

    So this solution works as long as the function called has a number of arguments equal to len(parts[1:]).

    Here is another example with two files.

    #  my_pack/__init__.py
    
    def fun1(x):
        print('x =', x)
    
    def fun2(x, y):
        print('x =', x, ', y =', y)
    
    
    #  test.py
    import my_pack
    
    args = [1]
    fun = getattr(my_pack, 'fun1')
    fun(*args)
    
    #  equivalent solution
    fun = getattr(my_pack, 'fun1')(*args)
    
    args = [1, 2]
    fun = getattr(my_pack, 'fun2')(*args)
    

    What @mgilson said is that this principle of calling a function without listing explicitly all its parameters but using the * operator is totally independent from getattr. As for instance here where I don't use getattr:

    def my_cool_func(a, b, c):
       print(a, b, c)
    
    my_cool_func(*[1, 2, 3])  #  prints "1 2 3"