[{"data":1,"prerenderedAt":772},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-identity-is-interning-explained":3},{"id":4,"title":5,"body":6,"description":758,"difficulty":759,"extension":760,"framework":761,"frameworkSlug":71,"meta":762,"navigation":352,"order":111,"path":763,"qaPath":764,"seo":765,"stem":766,"subtopic":767,"topic":768,"topicSlug":769,"updated":770,"__hash__":771},"blog\u002Fblog\u002Fpython-identity-is-interning-explained.md","Python Identity Explained — is vs ==, id(), and Integer\u002FString Interning",{"type":7,"value":8,"toc":748},"minimark",[9,14,42,46,66,181,189,193,207,288,295,299,314,384,393,397,404,487,499,503,524,589,595,599,605,698,702,744],[10,11,13],"h2",{"id":12},"python-identity-explained","Python identity, explained",[15,16,17,21,22,25,26,30,31,34,35,38,39,41],"p",{},[18,19,20],"code",{},"is"," and ",[18,23,24],{},"=="," look interchangeable until they suddenly aren't. The difference comes down to\n",[27,28,29],"strong",{},"identity"," versus ",[27,32,33],{},"equality",", and a CPython optimisation called ",[27,36,37],{},"interning"," that\nquietly reuses certain objects. Once you understand both, the \"random\" behaviour of ",[18,40,20],{},"\nbecomes completely predictable.",[10,43,45],{"id":44},"identity-vs-equality","Identity vs equality",[15,47,48,50,51,54,55,58,59,61,62,65],{},[18,49,24],{}," asks \"do these have the same ",[27,52,53],{},"value","?\" (via ",[18,56,57],{},"__eq__","). ",[18,60,20],{}," asks \"are these the\n",[27,63,64],{},"same object"," in memory?\" Two distinct objects can be equal; the same object is always\nboth.",[67,68,73],"pre",{"className":69,"code":70,"language":71,"meta":72,"style":72},"language-python shiki shiki-themes github-light github-dark","a = [1, 2, 3]\nb = [1, 2, 3]\na == b      # True  — same contents\na is b      # False — two separate list objects\nc = a\na is c      # True  — same object\n","python","",[18,74,75,109,131,145,157,168],{"__ignoreMap":72},[76,77,80,84,88,91,95,98,101,103,106],"span",{"class":78,"line":79},"line",1,[76,81,83],{"class":82},"sVt8B","a ",[76,85,87],{"class":86},"szBVR","=",[76,89,90],{"class":82}," [",[76,92,94],{"class":93},"sj4cs","1",[76,96,97],{"class":82},", ",[76,99,100],{"class":93},"2",[76,102,97],{"class":82},[76,104,105],{"class":93},"3",[76,107,108],{"class":82},"]\n",[76,110,112,115,117,119,121,123,125,127,129],{"class":78,"line":111},2,[76,113,114],{"class":82},"b ",[76,116,87],{"class":86},[76,118,90],{"class":82},[76,120,94],{"class":93},[76,122,97],{"class":82},[76,124,100],{"class":93},[76,126,97],{"class":82},[76,128,105],{"class":93},[76,130,108],{"class":82},[76,132,134,136,138,141],{"class":78,"line":133},3,[76,135,83],{"class":82},[76,137,24],{"class":86},[76,139,140],{"class":82}," b      ",[76,142,144],{"class":143},"sJ8bj","# True  — same contents\n",[76,146,148,150,152,154],{"class":78,"line":147},4,[76,149,83],{"class":82},[76,151,20],{"class":86},[76,153,140],{"class":82},[76,155,156],{"class":143},"# False — two separate list objects\n",[76,158,160,163,165],{"class":78,"line":159},5,[76,161,162],{"class":82},"c ",[76,164,87],{"class":86},[76,166,167],{"class":82}," a\n",[76,169,171,173,175,178],{"class":78,"line":170},6,[76,172,83],{"class":82},[76,174,20],{"class":86},[76,176,177],{"class":82}," c      ",[76,179,180],{"class":143},"# True  — same object\n",[15,182,183,185,186,188],{},[18,184,20],{}," never calls ",[18,187,57],{},"; it's a pure pointer comparison, which makes it fast and\nimpossible to fool.",[10,190,192],{"id":191},"id-reveals-the-object","id() reveals the object",[15,194,195,198,199,202,203,206],{},[18,196,197],{},"id(obj)"," returns a unique integer identifying the object for its lifetime — in CPython, its\nmemory address. ",[18,200,201],{},"x is y"," is exactly ",[18,204,205],{},"id(x) == id(y)",".",[67,208,210],{"className":69,"code":209,"language":71,"meta":72,"style":72},"a = [1, 2, 3]\nb = a\nid(a) == id(b)      # True\nid(a) == id([1, 2, 3])   # False — the literal is a different object\n",[18,211,212,232,240,259],{"__ignoreMap":72},[76,213,214,216,218,220,222,224,226,228,230],{"class":78,"line":79},[76,215,83],{"class":82},[76,217,87],{"class":86},[76,219,90],{"class":82},[76,221,94],{"class":93},[76,223,97],{"class":82},[76,225,100],{"class":93},[76,227,97],{"class":82},[76,229,105],{"class":93},[76,231,108],{"class":82},[76,233,234,236,238],{"class":78,"line":111},[76,235,114],{"class":82},[76,237,87],{"class":86},[76,239,167],{"class":82},[76,241,242,245,248,250,253,256],{"class":78,"line":133},[76,243,244],{"class":93},"id",[76,246,247],{"class":82},"(a) ",[76,249,24],{"class":86},[76,251,252],{"class":93}," id",[76,254,255],{"class":82},"(b)      ",[76,257,258],{"class":143},"# True\n",[76,260,261,263,265,267,269,272,274,276,278,280,282,285],{"class":78,"line":147},[76,262,244],{"class":93},[76,264,247],{"class":82},[76,266,24],{"class":86},[76,268,252],{"class":93},[76,270,271],{"class":82},"([",[76,273,94],{"class":93},[76,275,97],{"class":82},[76,277,100],{"class":93},[76,279,97],{"class":82},[76,281,105],{"class":93},[76,283,284],{"class":82},"])   ",[76,286,287],{"class":143},"# False — the literal is a different object\n",[15,289,290,291,294],{},"Note that ids can be ",[27,292,293],{},"reused"," after an object is freed, so don't store an id and compare\nit to a later object's id.",[10,296,298],{"id":297},"integer-interning-the-small-int-cache","Integer interning (the small-int cache)",[15,300,301,302,305,306,310,311,313],{},"CPython pre-creates and caches the integers ",[27,303,304],{},"-5 through 256",". Any reference to a value in\nthat range returns the ",[307,308,309],"em",{},"same"," cached object, so ",[18,312,20],{}," returns True. Outside that range, equal\nintegers are usually distinct objects.",[67,315,317],{"className":69,"code":316,"language":71,"meta":72,"style":72},"a = 100; b = 100\na is b          # True — both the cached 100\n\nx = 1000; y = 1000\nx is y          # often False — separate objects with the same value\n",[18,318,319,336,348,354,372],{"__ignoreMap":72},[76,320,321,323,325,328,331,333],{"class":78,"line":79},[76,322,83],{"class":82},[76,324,87],{"class":86},[76,326,327],{"class":93}," 100",[76,329,330],{"class":82},"; b ",[76,332,87],{"class":86},[76,334,335],{"class":93}," 100\n",[76,337,338,340,342,345],{"class":78,"line":111},[76,339,83],{"class":82},[76,341,20],{"class":86},[76,343,344],{"class":82}," b          ",[76,346,347],{"class":143},"# True — both the cached 100\n",[76,349,350],{"class":78,"line":133},[76,351,353],{"emptyLinePlaceholder":352},true,"\n",[76,355,356,359,361,364,367,369],{"class":78,"line":147},[76,357,358],{"class":82},"x ",[76,360,87],{"class":86},[76,362,363],{"class":93}," 1000",[76,365,366],{"class":82},"; y ",[76,368,87],{"class":86},[76,370,371],{"class":93}," 1000\n",[76,373,374,376,378,381],{"class":78,"line":159},[76,375,358],{"class":82},[76,377,20],{"class":86},[76,379,380],{"class":82}," y          ",[76,382,383],{"class":143},"# often False — separate objects with the same value\n",[15,385,386,387,389,390,392],{},"This is the classic interview trap: ",[18,388,20],{}," \"works\" for small numbers and breaks for large\nones. The lesson — never use ",[18,391,20],{}," to compare numeric values.",[10,394,396],{"id":395},"string-interning","String interning",[15,398,399,400,403],{},"Short, identifier-like string literals are ",[27,401,402],{},"interned"," (deduplicated) at compile time, so\nthey share one object. Strings built at runtime usually aren't.",[67,405,407],{"className":69,"code":406,"language":71,"meta":72,"style":72},"a = \"hello\"; b = \"hello\"\na is b              # True — interned literal\n\nx = \"\".join([\"he\", \"llo\"])\nx == a              # True\nx is a              # often False — built at runtime, not interned\n",[18,408,409,426,438,442,465,476],{"__ignoreMap":72},[76,410,411,413,415,419,421,423],{"class":78,"line":79},[76,412,83],{"class":82},[76,414,87],{"class":86},[76,416,418],{"class":417},"sZZnC"," \"hello\"",[76,420,330],{"class":82},[76,422,87],{"class":86},[76,424,425],{"class":417}," \"hello\"\n",[76,427,428,430,432,435],{"class":78,"line":111},[76,429,83],{"class":82},[76,431,20],{"class":86},[76,433,434],{"class":82}," b              ",[76,436,437],{"class":143},"# True — interned literal\n",[76,439,440],{"class":78,"line":133},[76,441,353],{"emptyLinePlaceholder":352},[76,443,444,446,448,451,454,457,459,462],{"class":78,"line":147},[76,445,358],{"class":82},[76,447,87],{"class":86},[76,449,450],{"class":417}," \"\"",[76,452,453],{"class":82},".join([",[76,455,456],{"class":417},"\"he\"",[76,458,97],{"class":82},[76,460,461],{"class":417},"\"llo\"",[76,463,464],{"class":82},"])\n",[76,466,467,469,471,474],{"class":78,"line":159},[76,468,358],{"class":82},[76,470,24],{"class":86},[76,472,473],{"class":82}," a              ",[76,475,258],{"class":143},[76,477,478,480,482,484],{"class":78,"line":170},[76,479,358],{"class":82},[76,481,20],{"class":86},[76,483,473],{"class":82},[76,485,486],{"class":143},"# often False — built at runtime, not interned\n",[15,488,489,490,493,494,496,497,206],{},"You can force interning with ",[18,491,492],{},"sys.intern(s)"," — useful when you have many duplicate strings\n(e.g. parsed tokens) and want fast ",[18,495,20],{}," comparisons and lower memory. But for ordinary code,\ncompare strings with ",[18,498,24],{},[10,500,502],{"id":501},"the-golden-rule-when-to-use-is","The golden rule: when to use is",[15,504,505,506,508,509,512,513,97,516,519,520,523],{},"Use ",[18,507,20],{}," ",[27,510,511],{},"only"," for singletons and genuine identity checks — never for values. The\ncanonical cases are ",[18,514,515],{},"None",[18,517,518],{},"True",", and ",[18,521,522],{},"False",", which are unique objects.",[67,525,527],{"className":69,"code":526,"language":71,"meta":72,"style":72},"if value is None: ...           # correct\nif flag is True: ...            # fine, but usually just: if flag\nif name == \"admin\": ...         # value comparison → use ==, never is\n",[18,528,529,551,570],{"__ignoreMap":72},[76,530,531,534,537,539,542,545,548],{"class":78,"line":79},[76,532,533],{"class":86},"if",[76,535,536],{"class":82}," value ",[76,538,20],{"class":86},[76,540,541],{"class":93}," None",[76,543,544],{"class":82},": ",[76,546,547],{"class":93},"...",[76,549,550],{"class":143},"           # correct\n",[76,552,553,555,558,560,563,565,567],{"class":78,"line":111},[76,554,533],{"class":86},[76,556,557],{"class":82}," flag ",[76,559,20],{"class":86},[76,561,562],{"class":93}," True",[76,564,544],{"class":82},[76,566,547],{"class":93},[76,568,569],{"class":143},"            # fine, but usually just: if flag\n",[76,571,572,574,577,579,582,584,586],{"class":78,"line":133},[76,573,533],{"class":86},[76,575,576],{"class":82}," name ",[76,578,24],{"class":86},[76,580,581],{"class":417}," \"admin\"",[76,583,544],{"class":82},[76,585,547],{"class":93},[76,587,588],{"class":143},"         # value comparison → use ==, never is\n",[15,590,591,592,594],{},"Using ",[18,593,20],{}," for value comparison may pass tests on small inputs and fail in production on\nlarger ones — exactly the kind of bug that hides until it's expensive.",[10,596,598],{"id":597},"mutability-and-identity","Mutability and identity",[15,600,601,602,604],{},"Identity matters for mutable objects: two names bound to the ",[307,603,309],{}," object see each other's\nmutations, while equal-but-distinct objects don't.",[67,606,608],{"className":69,"code":607,"language":71,"meta":72,"style":72},"a = [1, 2]; b = a               # same object\nb.append(3)\na                               # [1, 2, 3] — both names see it\nc = [1, 2]; d = list(c)         # distinct copies\nd.append(3)\nc                               # [1, 2] — unaffected\n",[18,609,610,635,645,653,681,690],{"__ignoreMap":72},[76,611,612,614,616,618,620,622,624,627,629,632],{"class":78,"line":79},[76,613,83],{"class":82},[76,615,87],{"class":86},[76,617,90],{"class":82},[76,619,94],{"class":93},[76,621,97],{"class":82},[76,623,100],{"class":93},[76,625,626],{"class":82},"]; b ",[76,628,87],{"class":86},[76,630,631],{"class":82}," a               ",[76,633,634],{"class":143},"# same object\n",[76,636,637,640,642],{"class":78,"line":111},[76,638,639],{"class":82},"b.append(",[76,641,105],{"class":93},[76,643,644],{"class":82},")\n",[76,646,647,650],{"class":78,"line":133},[76,648,649],{"class":82},"a                               ",[76,651,652],{"class":143},"# [1, 2, 3] — both names see it\n",[76,654,655,657,659,661,663,665,667,670,672,675,678],{"class":78,"line":147},[76,656,162],{"class":82},[76,658,87],{"class":86},[76,660,90],{"class":82},[76,662,94],{"class":93},[76,664,97],{"class":82},[76,666,100],{"class":93},[76,668,669],{"class":82},"]; d ",[76,671,87],{"class":86},[76,673,674],{"class":93}," list",[76,676,677],{"class":82},"(c)         ",[76,679,680],{"class":143},"# distinct copies\n",[76,682,683,686,688],{"class":78,"line":159},[76,684,685],{"class":82},"d.append(",[76,687,105],{"class":93},[76,689,644],{"class":82},[76,691,692,695],{"class":78,"line":170},[76,693,694],{"class":82},"c                               ",[76,696,697],{"class":143},"# [1, 2] — unaffected\n",[10,699,701],{"id":700},"recap","Recap",[15,703,704,706,707,709,710,712,713,706,715,717,718,720,721,724,725,727,728,730,731,733,734,97,736,97,738,740,741,743],{},[18,705,24],{}," compares ",[27,708,53],{}," (calls ",[18,711,57],{},"); ",[18,714,20],{},[27,716,29],{}," (same object, exactly\n",[18,719,205],{},"). CPython ",[27,722,723],{},"interns"," integers -5..256 and identifier-like string literals,\nso ",[18,726,20],{}," returns True for those and False for equal-but-separately-created values — which is\nwhy ",[18,729,20],{}," on numbers\u002Fstrings is a trap. Use ",[18,732,20],{}," only for ",[18,735,515],{},[18,737,518],{},[18,739,522],{},", and real\nidentity checks; use ",[18,742,24],{}," for everything value-related. Identity also explains why aliases of\na mutable object share mutations while copies don't.",[745,746,747],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":72,"searchDepth":111,"depth":111,"links":749},[750,751,752,753,754,755,756,757],{"id":12,"depth":111,"text":13},{"id":44,"depth":111,"text":45},{"id":191,"depth":111,"text":192},{"id":297,"depth":111,"text":298},{"id":395,"depth":111,"text":396},{"id":501,"depth":111,"text":502},{"id":597,"depth":111,"text":598},{"id":700,"depth":111,"text":701},"How object identity works in Python — the difference between is and ==, what id() returns, and why small-integer and string interning makes is behave in surprising ways.","medium","md","Python",{},"\u002Fblog\u002Fpython-identity-is-interning-explained","\u002Fpython\u002Finternals\u002Fidentity-interning",{"title":5,"description":758},"blog\u002Fpython-identity-is-interning-explained","Identity, is vs ==, & Interning","Memory & Internals","internals","2026-06-19","-IXnKtqJctunz_2mXwOM8ZR7t76Gm4_-ZREf0vbQm8Y",1782244092905]