3

In JavaScript it is possible to get a reference to the function when inside it, using a special variable/property arguments.callee. It can be useful, for example, to define recursive anonymous functions (but not only for that).

The same is not so easy in Python, as far as I know.

But I suppose it may possible using the inspect module, or some arcane techniques.

Could you please show me how it could be done?

I am ware of the questions

That is not what I'm looking for, though the names sound good.

martineau
  • 119,623
  • 25
  • 170
  • 301
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144
  • There is no such reference, which is why the two posts you refer to use hacks setting a reference to the function itself on the function object after it has been created. – Martijn Pieters Jan 19 '14 at 15:12
  • Other references: [Getting callable object from the frame](http://stackoverflow.com/q/1132543) and [Python: some "\_\_magic\_\_" attribute to reference a function from within that function](http://stackoverflow.com/q/14986523) – Martijn Pieters Jan 19 '14 at 15:19
  • Still more: [Getting the Python function for a code object](http://stackoverflow.com/q/12787108) – Martijn Pieters Jan 19 '14 at 15:24
  • E.g. the best you can get is the name given to the function object when it was constructed, to get the function object itself in a way that covers all possible corner cases is impossible (you can build a dynamic function object and directly call it, for example, nothing but the stack then has a reference the actual function object). – Martijn Pieters Jan 19 '14 at 15:29
  • Is the point of this post on how to create anonymous recursive functions in Python? Something akin to a `lambda`? – Spen-ZAR Jan 19 '14 at 15:33
  • @MartijnPeters: Thank you for the links. I need to check all of them. Some of them I've already seen, but what I've seen is not exactly what I'm looking for. Thank you very much once again – Igor Chubin Jan 19 '14 at 15:34
  • @Spen-ZAR: Yes, but not only that – Igor Chubin Jan 19 '14 at 15:35
  • @IgorChubin: What other goals are you planning to use this feature for? – Spen-ZAR Jan 19 '14 at 15:39
  • @Spen-ZAR: The main point is to understand all of the mentioned points better and become a python ninja. Iwant to understand what exactly I can do with functions in Python and how do it. As you can see, Martijn have referenced already almost a dozen of question, and none of them give (at least me) a clear answer to the question. That means that this question is even more important for undestarnding Python, than I've thaught before. – Igor Chubin Jan 19 '14 at 15:45
  • @IgorChubin: I'll poke around and see if I can get something working with a `lambda`. I've thought about this at one time or another. – Spen-ZAR Jan 19 '14 at 15:52
  • Here's a post I found about it. Hopefully it enhances your learning: [Can a lambda function call itself recursively in Python?](http://stackoverflow.com/questions/481692/can-a-lambda-function-call-itself-recursively-in-python) – Spen-ZAR Jan 19 '14 at 16:20
  • @Spen-ZAR: Thank you very much! There are so many interesting answers/questions on SO to the topic. That is amazing – Igor Chubin Jan 19 '14 at 16:22

1 Answers1

2

I assume you're aware that JavaScript's arguments.callee has been deprecated. Regardless, here's a couple of ways to do something similar in Python that you may not have seen yet.

Using a context manager:

class wrapped(object):
    def __init__(self, func):
        self.func = func
    def __enter__(self):
        def wrapper(*args, **kwargs):
            return self.func(self.func, *args, **kwargs)
        return wrapper
    def __exit__(self, *args):
        pass

def test(callee, value=None):
    if value is None:
        print 'function attribute "x" is {}'.format(callee.x)
    else:
        print 'setting function attribute "x" to {}'.format(value)
        callee.x = value

with wrapped(test) as test:
    test(42)  # -> setting function attribute "x" to 42
    test()    # -> function attribute "x" is 42

Another easier-to-use way would be with a function decorator:

from functools import wraps

def deco(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        return f(f, *args, **kwargs)
    return wrapper

@deco
def test(callee, value=None):
    if value is None:
        print 'function attribute "x" is {}'.format(callee.x)
    else:
        print 'setting function attribute "x" to {}'.format(value)
        callee.x = value

test(42)  # -> setting function attribute "x" to 42
test()    # -> function attribute "x" is 42
martineau
  • 119,623
  • 25
  • 170
  • 301