0

I'm wondering why this code returns same id of a variable. Doesn't interpreter suppose to clean a from memory after f() finished? Is this behavior result of some CPython optimization? Can we force it to clean a object? gc.collect() doesn't help in this. I thought that waiting for some time may change this behavior, but it doesn't.

import time

def f():
    a = "wat wat wat wat wat wat wat wat"
    print(id(a))

f()

for i in range(30):
    time.sleep(1)
    s = "/" if i % 2 == 0 else "\\"
    print(s, end="", flush=True)

print()
f()
# Tested with python 3.10.8
# 140443262854256
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
# 140443262854256
luk2302
  • 55,258
  • 23
  • 97
  • 137
Alpensin
  • 191
  • 1
  • 10

3 Answers3

1

This is due to a feature called string interning. When several string variables have the same value, Python only stores one copy of the string in memory. This optimization saves memory and allows string comparison to be performed faster. Note that this is a language-specific feature, and does not apply to programming languages in general. Also, string interning does not always happen, read more here.

Fractalism
  • 1,231
  • 3
  • 12
  • 1
    This doesn't necessarily have anything to do with interning. Object ids are only unique for the lifetime of the object, and the lifetimes of the `a` values created by the two calls to `f` don't overlap. – chepner Jan 28 '23 at 20:21
  • 1
    This seems wrong. [Try this](https://tio.run/##hcwxCoAwDIXhPacIdWkQXFxE8DAttdjBWtqCePoYdXHSQJbHz5eOumyxH1JmDmvacsVyFAA3e/SaRkA5gxOq3VT8eHWXKYdYdXDaEN1Dc3GdjHOOMgIICmD/QSVRK5XAD/pyLGEoaIn5BA). The output `True` for `sys.intern(b) is b` means `b` it wasn't interned already. But if I uncomment the explicit intern call in the function, the output changes to `False`. Meaning it took that explicit interning to actually get interned. – Kelly Bundy Jan 28 '23 at 20:21
  • In this article written Up until version 3.7, Python used peephole optimization, and all strings longer than 20 characters were not interned. However, now it uses the AST optimizer, and (most) strings up to 4096 characters are interned. I entered string more than 100 000 characters long but it still has same id – Alpensin Jan 28 '23 at 20:32
  • @chepner When I make the function [call itself recursively](https://tio.run/##K6gsycjPM7YoKPr/PyU1TSFNQ9OKSwEIEhVsFZTKE0sU8GAlsMqCosy8Eo3MFI1ETU2wANAMLi4g8f8/AA), the lifetimes of the calls do overlap. And the ids remain all the same. Which I think disproves *that* theory. – Kelly Bundy Jan 28 '23 at 20:48
  • Look at what `dis.dis` produces. The constant is part of the function definition itself, which doesn't involve string interning. – chepner Jan 28 '23 at 20:55
  • The standard example is `id([]) == id([])`, which usually returns `True`. Even though `[]` must produce a new list object in both cases, the first goes out of scope before the second one is created. – chepner Jan 28 '23 at 21:01
-1

GC in python does reference counting and deletes the objects automatically when no references to object left.

In your example, you still have the f function in your code at the end, keeping all the references to function f and everything in it alive.

To be able to assist GC, you can always delete the objects using del.

del f
altunyurt
  • 2,821
  • 3
  • 38
  • 53
-1

id returning the same value twice has nothing to do with a variable outliving its scope. Two objects whose lifetimes do not overlap can have the same id, as the id of the first is available to reuse for the second. Consider

>>> id([]) == id([])
True

[] always produces a new list object (as lists are immutable, you can't intern them). But this produces true because the list passed to the first call to id is reclaimed before the second call to id is made, meaning the second list can have the same id as the first.

chepner
  • 497,756
  • 71
  • 530
  • 681