1

A Python tutorial I came across mentions that new instances of local function are created every time the enclosing function is called.

I tried to test that out with below two examples:

Example 1: I am fetching object id of local function from within local function , new instances created for every function call. This work as expected.

    >>> def outer():
    ...  def inner():  
    ...   print(inner)
    ...  inner()
    ... 
    >>> outer()
    <function outer.<locals>.inner at 0x7f7b143bd620>
    >>> outer()
    <function outer.<locals>.inner at 0x7f7b143bd6a8>

Example 2: But when object id of local function is fetched from the outer function, Python doesn't seem to create new instances of local function for every call of outer function.

>>> def outer2():
...  def inner2():
...   pass   
...  print(inner2)
...  inner2()
... 
>>> outer2()
<function outer2.<locals>.inner2 at 0x7f7b143bd7b8>
>>> outer2()
<function outer2.<locals>.inner2 at 0x7f7b143bd7b8>

Can anyone please point out what is happening here?

i do understand that :

The id of an object is only guaranteed to be unique during that object's 
lifetime, not over the entire lifetime of a program.

my question here is :

why both examples behaves differently , although in both cases the object ceases to exist after print statement is executed.

vajravelu
  • 53
  • 1
  • 8
  • I don't fully understand the question – U13-Forward Sep 03 '18 at 04:11
  • https://stackoverflow.com/questions/17132047/same-value-for-idfloat – warvariuc Sep 03 '18 at 04:15
  • Try saving those functions in a global list then see if same memory address is used. – warvariuc Sep 03 '18 at 04:17
  • The function objects are re-using the memory address. The Python runtime efficiently re-uses previously allocated objects. Object `id`s are only guaranteed to be unique for the lifetime of the object. Note, in CPython, when an object's reference count reaches 0, it is "deallocated" immediately. Additionally, memory is managed by a [private heap](https://stackoverflow.com/a/14546231/5014455), which does many things, like caching. – juanpa.arrivillaga Sep 03 '18 at 06:03
  • I'm not really sure what the question is. Do you understand that `outer2() is outer2()` will return `False` even though it looks like both functions have the same ID? Do you understand that the same ID is being re-used for two different objects, and are asking why that doesn't happen in the first code snippet? – Aran-Fey Sep 04 '18 at 09:13
  • If you're asking specifically *"When does CPython re-use the same memory address?"*, then the answer to your question is just "That's undefined and arbitrary". It could be different in CPython 3.6 and CPython 3.6.1; it could be different from a 32-bit version in a 64-bit version; it could be different on Mac or linux. The answers in the duplicate do mention that this is an implementation detail and completely arbitrary. – Aran-Fey Sep 04 '18 at 09:25
  • `>>> outer2() is outer2() .inner2 at 0x7f0172bb86a8> .inner2 at 0x7f0172bb86a8> True` @Aran-Fey , Doesnt seem so. – vajravelu Sep 04 '18 at 09:28
  • @vajravelu Oops, I thought `outer2` returned the inner function. Of course, since your `outer2` doesn't return anything, `None is None` evaluates to True. The point is that the inner function is a different object every time, even though it may have the same ID. – Aran-Fey Sep 04 '18 at 09:32
  • @Aran-Fey , my question is why both the examples have consistently different kind of memory allocation, even though the objects in both the cases are gone as soon as the print statement is executed ? both the examples are executed from same python version and terminal ! – vajravelu Sep 04 '18 at 09:38
  • Coincidence. Clearly the two inner functions have a different function body (one of them is a closure function, while the other is not), and somehow as a result of that CPython ends up re-using the same ID for the `inner2` function. If you want to know how exactly that happens, you'll have to dig through the CPython source code. That's really far too broad for a SO question. – Aran-Fey Sep 04 '18 at 09:42
  • i am trying this from past two days and over a hundred times and results are exactly the same , and it cant be coincident 100 times :) – vajravelu Sep 04 '18 at 09:48
  • "Coincidence" doesn't mean "random". It's a coincidence that CPython was programmed this way. But as long as CPython's source code doesn't change, the behavior of your code won't change either. – Aran-Fey Sep 04 '18 at 10:10

0 Answers0