Home > Back-end >  Why does a wrapper that returns an inner function return a different copy of that inner function eac
Why does a wrapper that returns an inner function return a different copy of that inner function eac

Time:10-03

def outer():
    def inner(a):
        return a
    return inner

f = outer()
print(f)  # <function outer.<locals>.inner at 0x1044b61e0>

f2 = outer()
print(f2)  # <function outer.<locals>.inner at 0x1044b6268> (Different from above)

I know that f and f2 are different from each other.

But can someone tell me a precise explanation why they are different from each other?

Thank You

CodePudding user response:

The inner function is defined in the outer function. A new instance of this function is re-created every time you call outer.

Consider the following function:

a = 2

def not_so_inner():
    return a

You would expect it to always return 2, since a is a module variable.

Now, if I write the following function:

def outer(a):
    def inner():
        return a

    return inner

f1 = outer(1)
f2 = outer(2)

f1 and f2 are both a representation of the inner function, but bound to a different context where the a variable has a different value.

The return function must carry the outer context, so they are different instances of the function defined in the outer function.

CodePudding user response:

Observe that without the return statement involved, the id of the inner fuction inner is the same value, when outer() is called multiple times. This indicates that the inner function is actually pointing to the same reference value in memory.

>>> def outer():
...     print('outer() is being called.')
...     class A:
...         ...
...     def inner(a):
...         return a
...     print('id of class A:', id(A))
...     print('id of function inner():', id(inner))
...
>>> outer()
outer() is being called.
id of class A: 2098069832976
id of function inner(): 2098062549056
>>> outer()
outer() is being called.
id of class A: 2098069814096
id of function inner(): 2098062549056

Notice that the line id of function inner(): ... indicates that the id values for inner() are the same in either case.

When you introduce a return statement, then things become a little more interesting. It looks like the id value is different each time, which indicates a new inner() function is being created on each invocation of outer().

def outer():
    print('outer() is being called.')

    class A:
        ...

    def inner(a):
        return a

    print('  id of class A:', id(A))
    print('  id of function inner():', id(inner))

    return inner


inner1 = outer()
inner2 = outer()
inner3 = outer()
print()
print(id(inner1))
print(id(inner2))
print(id(inner3))

Sample output:

outer() is being called.
  id of class A: 2175736425280
  id of function inner(): 2175746787792
outer() is being called.
  id of class A: 2175736423360
  id of function inner(): 2175746786496
outer() is being called.
  id of class A: 2175736424320
  id of function inner(): 2175746788080

2175746787792
2175746786496
2175746788080

Now I'm not entirely sure if this post answers your question, however it is certainly food for thought and for future consideration.

Using the builtin id() function in Python, you can confirm that a new inner() function is being created on each run, at least in regards to the second case above.

  • Related