Is there a generic way for a function to reference itself?
Asked Answered
M

4

47

I can access a python function's attribute inside of function itself by below code:

def aa():
    print aa.__name__
    print aa.__hash__
    # other simliar

However, if above aa() function is a template for write other code, say bb(), I have to write:

def bb():
    print bb.__name__
    print bb.__hash__
    # other simliar

Is there a "pointer" similar to the self argument in a class method so I could write code like this?

def whatever():
    print self.__name__
    print self.__hash__
    # other simliar

I searched and found someone said to use the class to solve this problem, but that may be a trouble to redefine all the existing functions. Any suggestions?

Mastoid answered 21/2, 2011 at 8:7 Comment(3)
self is not a magic keyword. It is explicitly defined as the first argument to an instance-based function.Locoweed
I'm curious. Why do you need this prologue in many functions? Is it merely for debugging?Lustral
@Beni, yes, for prototype a basic model in very "rapid" way.Mastoid
M
37

There is no generic way for a function to refer to itself. Consider using a decorator instead. If all you want as you indicated was to print information about the function that can be done easily with a decorator:

from functools import wraps
def showinfo(f):
    @wraps(f)
    def wrapper(*args, **kwds):
         print(f.__name__, f.__hash__)
         return f(*args, **kwds)
    return wrapper

@showinfo
def aa():
    pass

If you really do need to reference the function, then just add it to the function arguments:

def withself(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        return f(f, *args, **kwds)
    return wrapper

@withself
def aa(self):
      print(self.__name__)
      # etc.

Edit to add alternate decorator:

You can also write a simpler (and probably faster) decorator that will make the wrapped function work correctly with Python's introspection:

def bind(f):
    """Decorate function `f` to pass a reference to the function
    as the first argument"""
    return f.__get__(f, type(f))

@bind
def foo(self, x):
    "This is a bound function!"
    print(self, x)


>>> foo(42)
<function foo at 0x02A46030> 42
>>> help(foo)
Help on method foo in module __main__:

foo(self, x) method of builtins.function instance
    This is a bound function!

This leverages Python's descriptor protocol: functions have a __get__ method that is used to create bound methods. The decorator simply uses the existing method to make the function a bound method of itself. It will only work for standalone functions, if you wanted a method to be able to reference itself you would have to do something more like the original solution.

Matriarchate answered 21/2, 2011 at 8:37 Comment(2)
As explained in the answer from @akira, there is a generic way for a function to refer to itself, namely using sys._getframe().f_code.co_name. So this answer, although potentially useful, starts with a false claim and IMHO shouldn't be elected "best answer" if there is a correct and more precise and satisfying answer to the question.Cleaning
@Cleaning sorry but I stand by my claim. globals()[sys._getframe().f_code.co_name] won't work for a nested function, or for a function that has been deleted from the module where it was declared. e.g. inside a decorated function it will give you the wrapper rather than the original function.Matriarchate
S
20

http://docs.python.org/library/inspect.html looks promising:

import inspect
def foo():
     felf = globals()[inspect.getframeinfo(inspect.currentframe()).function]
     print felf.__name__, felf.__doc__

you can also use the sys module to get the name of the current function:

import sys
def bar():
     felf = globals()[sys._getframe().f_code.co_name]
     print felf.__name__, felf.__doc__
Synergy answered 21/2, 2011 at 8:23 Comment(5)
And a lot more work than just referring to the function explicitly.School
@FLorian Mayer: thats true, thats why i +1 @Matriarchate for the self-decorator.Synergy
this is exactly what was asked for... and, while it is not direct and simple I don't think that the decorated version is as clear. (IMO)Archimandrite
This answer should be elected as "best" because it exactly answers the question while the current "best" answer starts with the incorrect assertion that there is no generic way a function can get a reference to itself: The last piece of code above proves that there is! (Namely: sys._getframe().f_code.co_name is the function's name)Cleaning
@Florian Mayer: It is not "a lot more work", but exactly what is needed. On one hand, on the average (over all possible function names) this code is extremely short compared to typing out the function's name. [No max. length => infinite average length.] On the other hand, the question becomes obviously most relevant when for some reason the function is no more assigned to the same variable (aka function name) to which it was originally assigned to. (It may have been copied to a different variable and the original name reused, as in a context of funtion overloading.)Cleaning
G
0

You can at least say self = bb in the first line, and then you only need to change that line when you change the function name, instead of every other reference.

My code editor highlights the variable self the same way it does for classes, too.

Garnet answered 18/8, 2019 at 12:49 Comment(0)
I
-6

How about a quick hack to make your own "self" name, like this:

>>> def f():
...     self = f
...     print "My name is ", self.__name__, "and I am", self.__hash__
...
>>> f()
My name is  f and I am <method-wrapper '__hash__' of function object at 0x00B50F30>
>>> x = f
>>> x()
My name is  f and I am <method-wrapper '__hash__' of function object at 0x00B50F30>
>>>
Infelicity answered 7/8, 2012 at 14:24 Comment(2)
Surely this is no different from the OP referring to f.__name__?Drennan
So x's name is f... this doesn't answer the question at allSpica

© 2022 - 2024 — McMap. All rights reserved.