5

I have defined a function within another function in python and now I would like to call the inner function. Is this possible, in python? How do I call func2 from func3?

def func1():
    def func2():
        print("Hello!")

def func3():
    # Enter code to call func2 here
vvvvv
  • 25,404
  • 19
  • 49
  • 81
Rohan Sawant
  • 938
  • 1
  • 11
  • 18
  • 1
    You can not, since a function is procedural, you define the function when you a specific `func2()` when you call `func1()`. If you call `func1()` multiple times, you will define several `func2`s. Furthermore since it is procedural, it is possible that `func2` is never declared (in an `if` statement). Here you do not return the function, so unless with debugger-like hacking, that would be close to impossible. – Willem Van Onsem Jan 01 '18 at 12:01
  • 1
    But why have you defined it inside another function? If you want to call `func2` without calling `func1`, then it should be outside `func1`. Maybe your both functions are better fit for single class?? – Moinuddin Quadri Jan 01 '18 at 12:02
  • Search the python dokumentation, google and SO for topics that might answer your question before asking - you could have found f.e. this: [short-description-of-the-scoping-rules](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) – Patrick Artner Jan 01 '18 at 12:05
  • 1
    What do **actually** want to achieve ? – Evya Jan 01 '18 at 12:05
  • @PatrickArtner I will keep that in mind next time :), Evyatar I was trying something dirty, I had added those functions in the run() function of Thread Class, it was something hacky, dirty and wrong but I was curious nevertheless. – Rohan Sawant Jan 01 '18 at 12:30
  • I'm not recommending it, but there is a way: see my updated answer. – mhawke Jan 01 '18 at 12:31
  • @mhawke oh!, that's beautiful! and no I am not using that in my source code, I was just curious how much we could really bend Python. :) – Rohan Sawant Jan 01 '18 at 12:34

2 Answers2

16

You can't, at least not directly.

I'm not sure why you would want to do that. If you want to be able to call func2() from outside func1(), simply define func2() at an appropriate outer scope.

One way that you could do it is to pass a parameter to func1() indicating that it should invoke func2():

def func1(call_func2=False):
    def func2():
        print("Hello!")
    if call_func2:
        return func2()

def func3():
    func1(True)

but since that requires modification to the existing code, you might as well move func2() to the same scope as func1().


I don't recommend that you do this, however, with some indirection you can reach into the func1() function object and access it's code object. Then using that code object access the code object for the inner function func2(). Finally call it with exec():

>>> exec(func1.__code__.co_consts[1])
Hello!

To generalise, if you had multiple nested functions in an arbitrary order and you wanted to call a specific one by name:

from types import CodeType
for obj in func1.__code__.co_consts:
    if isinstance(obj, CodeType) and obj.co_name == 'func2':
        exec(obj)
mhawke
  • 84,695
  • 9
  • 117
  • 138
4

Let's go into little deep and explore it :

You can do this via three methods :

First method:

Just return the nested function from main function so return will become the caller of nested function:

def func1():
    def func2():
        print("Hello!")
    return func2()


def func3():
    return func1()

func3()

output:

Hello!

Second method : Even you can pass argument directly to nested function:

Using Closure concept :
def func1():
    def func2(x):
        print("Hello {}".format(x))
    return func2

closure=func1()
def func3():
    return closure('bob')

func3()

Look above example , Main function is not accepting any parameter but nested function have one parameter so here i directly pass the argument to nested function.

Third method :

You can try this little hacky thing :

def func1():
    def func2():
        print("Hello")
    return func2


def func3():
    return func1()()

func3()