3

This answer shows that there is a built-in __name__ attribute of a function which can be used from outside the function, i.e. print f.__name__. However, how can I get this attribute from within the function itself?

Just using unqualified __name__ does not help: print __name__ prints __main__.

Using print f.__name__ from within f() looks stupid - I can type "f" just as well.

Alternatively, is there a kind of self object for functions, i.e. can I get a pointer to the function that is executing in a common way?

I don't like the method proposed in this question - it feels that hacking the stack for such simple task is not the proper way.

Motivation: I have a dictionary of {keyword:function}, the keywords are read from the input and an appropriate function is executed. I want each function to be executed only once, so I want each function to register itself in some data structure when executed. I know I can do it in the dictionary itself, but I thought of using a separate data structure for this.

Python version is 2.6.4 BTW

Community
  • 1
  • 1
davka
  • 13,974
  • 11
  • 61
  • 86
  • 1
    Just link to this answer, which solves the questions in the title: http://stackoverflow.com/a/5067654/547578 – Fish Monitor Mar 23 '13 at 13:17
  • thanks @fossilet but as I say in the question playing with the call stack for this feels... don't know, too hacky – davka Mar 24 '13 at 13:59
  • 1
    I find it humorous that you find inspect to be "too hacky". Granted the syntax of navigating the multi-dimensional stack probably warrants reading the docs, but it's effective. Here's another hacky one that might be fun: pass the function as an argument to itself. – afeique Oct 10 '17 at 18:24

2 Answers2

4

if you don't want to "inspect" the stack, you could use a decorator on your method to store it in your dictionnary and avoid to launch it twice.

function_list = []
def method_singleton(function):
    global function_list
    def decorated_method(*args, **kwargs):
        if function.__name__ not in function_list:
            function_list.append(function.__name__)
            return function(*args, **kwargs)
        else:
            print "Method %s already called"%function.__name__
    return decorated_method

@method_singleton
def method_to_decorate(arg1, arg2):
    pass

where "function_list" is the list of functions already called (i don't know how you manage your dictionnary)

Cédric Julien
  • 78,516
  • 15
  • 127
  • 132
  • now that I know about decorators thanks to your answers :), doesn't your solution check the `function_list` only once, when the the function is defined and decorated? Shouldn't the check be dynamic, every time the function is executed? – davka Apr 26 '11 at 13:47
  • oh, yes, you're right ;) to do it at call, you'll have to move the test into the decorated method – Cédric Julien Apr 26 '11 at 13:51
3

Perhaps you should decorate each function that you're calling with an onlyonce decorator? That would be more pythonic. A proof of concept follows.

called = set()

def onlyonce(fn):
    def decorated(*largs, **kargs):
        if fn not in called:
            called.add(fn)
            print "Calling"
            fn(*largs, **kargs)
        else:
            print "Already called"
    return decorated



@onlyonce
def test_function():
    print "I am getting called now"


test_function()
test_function()
test_function()
test_function()

Also, functions are "immutable" and can be stored as dictionary keys. You don't have to rely on the names. This might be an advantage (or a disadvantage) depending on your use.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169