2

Lets say I have a function foo:

def foo():
    print('something')

and I am passing this above function to lambda function along with assigning it to a variable.

bar = lambda: foo

So, if I have the bar object how can I extract that name of the function that was passed to it i.efoo?

I tried to list all the methods of that bar object using dir(bar), couldn't find much to extract the desired result.

Abhimanyu
  • 725
  • 1
  • 6
  • 20
  • Note that this has nothing to do with higher-order functions or lambdas, this is just the way to get the name of something in Python. – Cedric H. Sep 11 '19 at 13:45
  • You're not passing `foo` into a lambda function here. You're writing a lambda function that returns it. What are you trying to do? – Holloway Sep 11 '19 at 13:45
  • why are you using a lambda that has no params and returns `foo`. Just use `foo`? – Pynchia Sep 11 '19 at 13:47
  • @Pynchia it just and sample example that I showed the real use case is a bit complex and of course I am passing argument. – Abhimanyu Sep 11 '19 at 13:51
  • @Holloway related to this answer, https://stackoverflow.com/a/45279060/5964750 – Abhimanyu Sep 11 '19 at 13:58
  • 1
    I think you could do with updating the question to better match your use case. If you're actually using `bar = lambda x: foo(x)` there is no way to extract the name `foo` from bar (except maybe via some dis/ast hack). – Holloway Sep 11 '19 at 14:01
  • @Holloway I have a combination of functions passed with the post_save of different model instance. Now I want to write test cases to check conditions like `foo1` will be passed inside post_save event of model `M1` post save, `foo2` will be passed for post save of model `M2` and so on. – Abhimanyu Sep 11 '19 at 14:08
  • @Error-SyntacticalRemorse, I agree the example is a bit odd but `bar = lambda: foo` and `bar = foo` are not the same. – Holloway Sep 11 '19 at 14:11
  • @Holloway I agree they are slightly different. The lambda returns `foo` as a callable which needs to be called again. There is almost never a need for this unless you are monkey typing in default variables. – Error - Syntactical Remorse Sep 11 '19 at 14:15

3 Answers3

4

You can't directly do that, but you can call bar, which returns foo, and check its __name__ attribute:

>>> bar().__name__
'foo'
Right leg
  • 16,080
  • 7
  • 48
  • 81
0

Why are you doing bar = lambda: foo instead of just bar = foo? The lambda returns a the foo object meaning you have to do something like:

bar = lambda: foo
# now to call foo:
bar()()

Functions are first class objects in python so you don't need a lambda for something this simple.

bar = foo
print(bar.__name__) # foo
# now to call foo:
bar()

It would be a different story if you wanted to pass default arguments:

def foo(x, y, z):
    print(x, y, z)
y = 3
z = 2
bar = lambda x, y=y, z=z: foo(x, y, z)
# now to call foo:
bar(1) # 1 3 2
# but printing the name is this case is more tricky since the 
# lambda isn't return the function object but the return value
# of that function.
# Thus you would need to use inspect like the answer below.
  • `bar(1).__name__` wouldn't work with that example because it'd be reading the `__name__` attribute on whatever `foo` returns not `foo` itself (in this case `None`). – Holloway Sep 11 '19 at 14:23
-1

If you do not want to call the function to get his name (as suggested in other answers), you can inspect your function to get the code, and from there work your way out to get the passed function's name:

def foo():
    print('something')

bar = lambda: foo

print(inspect.getsource(bar))

Output:

bar = lambda: foo

And finding the provided function shouldn't be complicated, i.e.:

func_code = inspect.getsource(bar)
passed_function = func_code.split(' ')[-1]

print(passed_function)

Output:

foo

Even if you have multiple arguments, you can extract the provided function's name:

import inspect


def foo(x, y, z):
    print('something')

bar = lambda x, y, z: foo(x, y, z)

func_code = inspect.getsource(bar)
print(func_code)
passed_function = func_code.split('(')[0].split(' ')[-1]

print(passed_function)

Output:

foo

Gsk
  • 2,929
  • 5
  • 22
  • 29
  • This is incredibly fragile, eg I could write a `bar = lambda:foo` or `bar = lambda x,y,z : foo(x, y, z)` and it'd fail, even if the variable is exactly the same. – Holloway Sep 11 '19 at 14:09
  • I do get your point, but that's a different problem. It looks fragile because that's an example, but parsing and extracting function's name is how [static analysis tools](http://opensourceforu.com/2011/09/joy-of-programming-technology-behind-static-analysis-tools/) works. – Gsk Sep 11 '19 at 14:17
  • If you were running the source through `ast.parse` or similar, then yes, it would be possible but I doubt any static analysis tools rely on splitting on whitespace. – Holloway Sep 11 '19 at 14:21
  • @Holloway splitting on whitespaces was an example; [examples](https://en.wiktionary.org/wiki/example#English) is a _non-exhaustive_ conceptualization representative of a bigger group (in this case, parsing). Static analysis tools do not rely on that, but they do [parse the code](http://opensourceforu.com/2011/09/joy-of-programming-technology-behind-static-analysis-tools/)! so: understood the critique, not the case. – Gsk Sep 11 '19 at 14:31