0

How do you use name with a function that I'd like to pass a keyword argument through?

For example, I have the following function:

def func(keyword1='A'):
     print keyword1

I can do this:

func.__name__
>> 'func'

But, I'd like to do this:

func(keyword1='B').__name__
>>> 'func'

The reason I'd like to do this is because I have another method that takes in this function as an argument and it needs to pull the name of the function and run that function with different keywords.

So, what I'm really trying to do is get this function to work:

def Function_Name_And_Result(x):
    print x.__name__ + x()

Function_Name_And_Result(func(keyword1='B'))
>> funcB
Chris
  • 4,194
  • 9
  • 52
  • 100
  • And what would be your expected output for the code snippet that you would like to make work? Could you include a minimal example of what kind of thing it would be? – anon582847382 Apr 11 '14 at 10:43
  • 2
    **Why** would you do that? The **return value** of the function call has no `.__name__` attribute. Calling the function and retrieving an attribute on the function object are two **entirely separate things**. – Martijn Pieters Apr 11 '14 at 10:44
  • 1
    Could this be an [X-Y problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) ? – anon582847382 Apr 11 '14 at 10:45
  • I tried to answer your questions above around why. The essence of the reason is that I have another function that I'd like to really use that gets both the name of the input function and the output of the input function. The issue is that the input function has keywords that I'd like to change – Chris Apr 11 '14 at 10:47

2 Answers2

5

Python's functions are objects too, so you can pass them along just like any other object. What you're doing (which can't obviously work) is passing the result of calling the function. What you want is to pass the function and the function's argument:

def print_function_name_and_result(func, *args, **kw):
    print "%s : %s" % (func.__name__, func(*args, **kw))

print_function_name_and_result(func, keyword1='B')
>> func : B
bruno desthuilliers
  • 68,994
  • 6
  • 72
  • 93
  • Since `__name__` shouldn't be directly used (since it's surrounded by two '_'s), maybe using `inspect.stack()` might be better? Of course that would mean saving the stack from `x` but it might be safer since you can ensure you're not modifying the `__name__` by mistake. – Tejas Pendse Apr 11 '14 at 10:52
  • @mogambo: there are cases where breakin some "golden rule" is ok and this is one as far as I'm concerned. Resorting to `inspect.stack` for such a simple need is really overkill IMHO. – bruno desthuilliers Apr 11 '14 at 10:56
  • @mogambo: It is perfectly fine to access a documented attribute like `__name__` directly. There is no more specific API for accessing it in any case. I fail to see how `inspect.stack()` would be a better choice here. – Martijn Pieters Apr 11 '14 at 10:58
  • I didn't know that! I always thought since python can't enforce scoping (like C++'s private/public scopes), you had use underscores to dissuade the user not to use an internal function. [I can see I was misinformed](http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private) :) – Tejas Pendse Apr 11 '14 at 11:27
  • @mogambo: a single leading underscore denotes a "private" attribute / method. `__magic__` names (two leading and two trailing underscores) are reserved for the language's implementation (iow you shouldn't use that scheme yourself), and most of the times are used for operators / operator-like functions support in which case you should use the operator or function instead (ie `1 + 2` instead of  `1.__add__(2)`). There's no operator nor generic function for accessing a function or class `__name__` attribute so it's ok to use it directly. – bruno desthuilliers Apr 13 '14 at 15:55
  • Thanks for the info, @brunodesthuilliers! – Tejas Pendse Apr 14 '14 at 08:40
3

If you have a method that takes a function, then pass in the function, not the return value.

You are instead calling the function. The .__name__ attribute lookup is applied to the return value of that call. If you are passing the return value of a function call to your method, you are not passing the function object itself.

If you need to pass in a function that needs to be called with certain arguments by the method, you can pass in those extra arguments instead, and have the method use those arguments for you:

def Function_Name_And_Result(x, *args, **kw):
    print x.__name__, x(*args, **kw)

Now you can still pass in your function object itself:

Function_Name_And_Result(func, keyword1='B')

Demo:

>>> def Function_Name_And_Result(x, *args, **kw):
...     print x.__name__, x(*args, **kw)
... 
>>> def func(keyword1='A'):
...      print keyword1
... 
>>> Function_Name_And_Result(func, keyword1='B')
func B
None
Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997