[{"data":1,"prerenderedAt":67},["ShallowReactive",2],{"qa-\u002Fpython\u002Finternals\u002Fidentity-interning":3},{"page":4,"siblings":57,"blog":48},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"related":48,"seo":49,"seoDescription":50,"stem":51,"subtopic":52,"topic":53,"topicSlug":54,"updated":55,"__hash__":56},"qa\u002Fpython\u002Finternals\u002Fidentity-interning.md","Identity Interning",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","Python","python",{},true,"\u002Fpython\u002Finternals\u002Fidentity-interning",[22,26,30,34,38,43],{"id":23,"difficulty":14,"q":24,"a":25},"is-vs-equals","What is the difference between is and ==?","**`==`** tests **value equality** — \"do these represent the same data?\" — by\ncalling the object's `__eq__`. **`is`** tests **identity** — \"are these the\n*exact same object* in memory?\" — which is effectively an `id()` comparison. They\nfrequently agree, but conceptually they ask completely different questions.\n\n```python\na = [1, 2, 3]\nb = [1, 2, 3]\na == b      # True  — equal contents\na is b      # False — two distinct list objects\n\nc = a\nc is a      # True  — same object, just another name\n```\n\nUse `==` whenever you care about the **value**, which is almost always. Reserve\n`is` for **identity** checks against singletons. Rule of thumb: if you're\ncomparing data, use `==`; if you're checking \"is this literally that object,\" use\n`is`.\n",{"id":27,"difficulty":14,"q":28,"a":29},"id-function","What does the id() function tell you?","**`id(obj)`** returns a unique integer **identity** for an object that's constant\nfor the object's **lifetime**. In **CPython** it's the object's **memory\naddress**, though that's an implementation detail. Two names with the same `id`\nrefer to the **same object**, and `is` is essentially an `id` comparison.\n\n```python\na = [1, 2]\nb = a\nid(a) == id(b)   # True  — same object\na is b           # True  — equivalent check\n\nc = [1, 2]\nid(a) == id(c)   # False — equal value, different object\n```\n\n`id` is handy for understanding **aliasing** — why mutating through one name\nshows up through another. Don't rely on the actual numeric value (it can be\nreused after an object is garbage-collected); use it only to reason about\nsameness.\n",{"id":31,"difficulty":14,"q":32,"a":33},"small-int-cache","What is the small-int cache?","CPython **pre-creates and caches integers from −5 to 256** as singletons at\nstartup. Any time a value in that range is needed, the **same cached object** is\nreused — so equal small ints share identity and `is` returns `True`. Outside that\nwindow, equal integers are typically **distinct** objects.\n\n```python\na = 256\nb = 256\na is b      # True  — both point at the cached 256\n\nc = 257\nd = 257\nc is d      # often False — separate objects\nc == d      # True  — always compare values with ==\n```\n\nThis is purely a **memory\u002Fperformance optimization** and a CPython\nimplementation detail — not a language guarantee. It's the single biggest reason\n`is` \"appears\" to work on numbers. Rule of thumb: never use `is` to compare ints,\nuse `==`.\n",{"id":35,"difficulty":14,"q":36,"a":37},"string-interning","What is string interning and sys.intern?","**Interning** stores a **single shared copy** of a string so identical strings\ncan be the **same object**, saving memory and making equality checks a fast\npointer comparison. CPython **auto-interns** short, identifier-like string\nliterals (and compile-time constants); other strings may not be. You can force it\nwith **`sys.intern`**.\n\n```python\na = \"hello\"\nb = \"hello\"\na is b           # True  — auto-interned literal\n\nc = \"hello world!\"\nd = \"hello world!\"\nc is d           # often False — not auto-interned\n\nimport sys\ne = sys.intern(\"hello world!\")\nf = sys.intern(\"hello world!\")\ne is f           # True — explicitly interned\n```\n\n`sys.intern` is useful when you compare the **same strings repeatedly** (parsing,\ntokenizing, dict keys) and want the speed\u002Fmemory win. Like int caching, which\nstrings auto-intern is an **implementation detail** — never rely on it for\ncorrectness.\n",{"id":39,"difficulty":40,"q":41,"a":42},"is-coincidental","hard","Why does is sometimes \"work\" coincidentally?","`is` sometimes returns `True` for equal values **only because CPython caches or\ninterns those particular objects** — small ints (−5..256) and many short string\nliterals share one object. It's an accident of optimization, not equality, so it\nbreaks the moment you leave the cached range.\n\n```python\nx = 100\nx is 100         # True  — cached small int (deceiving!)\n\ny = 1000\ny is 1000        # often False — outside the cache\ny == 1000        # True  — the correct comparison\n```\n\nThe danger is that code passes during testing with small values and then fails in\nproduction with larger ones. Treat any `is`-on-a-value that works as a **lucky\ncoincidence**. Rule of thumb: if swapping `is` for `==` would change behavior on\n*some* input, you should have used `==`.\n",{"id":44,"difficulty":45,"q":46,"a":47},"correct-use-of-is","easy","What is the correct use of is?","Use `is` to test **identity against singletons** — objects of which there is\nexactly **one** — most commonly **`None`**, but also `True`, `False`, and your own\n**sentinel** objects. For singletons `is` is correct, fast, and can't be fooled by\na custom `__eq__`.\n\n```python\nif x is None:          # idiomatic, recommended by PEP 8\n    ...\n\n_MISSING = object()    # unique sentinel\ndef get(d, key, default=_MISSING):\n    val = d.get(key, _MISSING)\n    if val is _MISSING:    # distinguishes \"absent\" from \"value is None\"\n        return default\n    return val\n```\n\nA sentinel like `object()` is ideal precisely because `is` checks identity — no\nother object can ever match it. Rule of thumb: `is`\u002F`is not` for `None` and\nsentinels; `==`\u002F`!=` for everything else.\n",null,{"description":11},"Python interview questions on object identity: is vs ==, the id() function, the small-int cache, string interning, and the correct use of is for None and sentinels.","python\u002Finternals\u002Fidentity-interning","Identity, is vs ==, & Interning","Memory & Internals","internals","2026-06-18","Bxm0c6IuOw0YEDIc513jbfs-3-is_vtYIBOUhOkjzzY",[58,62,63],{"subtopic":59,"path":60,"order":61},"Garbage Collection & Reference Counting","\u002Fpython\u002Finternals\u002Fgarbage-collection",1,{"subtopic":52,"path":20,"order":12},{"subtopic":64,"path":65,"order":66},"The CPython Execution Model","\u002Fpython\u002Finternals\u002Fcpython-model",3,1781808681307]