π Object Identity β is vs ==
Python provides two different operators for comparing objects:
==β Checks whether values are equalisβ Checks whether two variables refer to the same object
βοΈ == β Value Comparison
The == operator checks whether two objects have the same value.
x = [1, 2, 3]
y = [1, 2, 3]
print(x == y) #TrueEven though x and y are separate lists, their contents are the same.
π is β Identity Comparison
The is operator checks whether two variables refer to the exact same object in memory.
x = [1, 2, 3]
y = [1, 2, 3]
print(x is y) #Falsex and y contain the same values, but they are two different list objects.
π Same Object Example
x = [1, 2, 3]
y = x
print(x == y) # True
print(x is y) # TrueHere, y = x makes both variables refer to the same object.
β Important Example with None
is is commonly used when checking for None:
name = None
if name is None:
print("No name provided")Prefer:
name is Noneover:
name == Noneπ is vs ==
|
|
|---|---|
Compares values | Compares identity |
Asks: "Are they equal?" | Asks: "Are they the same object?" |
Uses equality comparison | Checks object identity |
Example: | Example: |
π§ Easy Way to Remember
== β Same VALUE? π°
is β Same OBJECT? π<div class="infographic-pyisEq">
<style>
.infographic-pyisEq {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--true-c: #1f9d55; --true-soft: #e3f5ec;
--false-c: #c0392b; --false-soft: #fbe9e7;
--warn: #b45309; --warn-soft: #fdf0dc;
--mono-font: 'IBM Plex Mono', 'SFMono-Regular', Menlo, monospace;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', system-ui, sans-serif;
box-sizing: border-box;
max-width: 780px;
margin: 0 auto;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.infographic-pyisEq[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--true-c: #6fdc8c; --true-soft: #1c3324;
--false-c: #e57373; --false-soft: #3a2222;
--warn: #e0a458; --warn-soft: #3a2c14;
}
.infographic-pyisEq *, .infographic-pyisEq *::before, .infographic-pyisEq *::after { box-sizing: border-box; }
.infographic-pyisEq .ie-wrap { padding: 0 clamp(1rem, 4vw, 2rem) 1.5rem; }
.infographic-pyisEq h1 {
font-family: var(--display-font); font-weight: 600;
font-size: clamp(1.5rem, 5vw, 2.05rem); text-align: center; margin: 1.5rem 0 0.25rem; letter-spacing: -0.01em;
}
.infographic-pyisEq .ie-sub { text-align: center; color: var(--ink-soft); font-size: 0.86rem; margin: 0 0 1.4rem; }
.infographic-pyisEq .rule-row { display: flex; justify-content: center; gap: 0.8rem; margin-bottom: 1.4rem; flex-wrap: wrap; }
.infographic-pyisEq .rule-card {
flex: 1 1 220px; max-width: 260px; text-align: center; border-radius: 10px; padding: 0.7rem 0.9rem;
font-family: var(--mono-font); border: 1.5px solid var(--line); background: var(--paper-alt);
}
.infographic-pyisEq .rule-card .op { font-family: var(--display-font); font-size: 1.3rem; font-weight: 600; color: var(--accent); }
.infographic-pyisEq .rule-card .desc { font-size: 0.78rem; color: var(--ink-soft); font-family: var(--body-font); margin-top: 0.2rem; }
.infographic-pyisEq .scenario-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.4rem; margin-bottom: 1.2rem; }
.infographic-pyisEq .scenario-btn {
font: inherit; font-family: var(--mono-font); font-size: 0.78rem; font-weight: 700;
background: var(--paper-alt); border: 1.5px solid var(--line); color: var(--ink-soft);
padding: 0.4rem 0.7rem; cursor: pointer; border-radius: 6px;
}
.infographic-pyisEq .scenario-btn.is-selected { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.infographic-pyisEq .decl-line {
text-align: center; font-family: var(--mono-font); font-size: 0.88rem; color: var(--ink-soft); margin-bottom: 1.1rem;
}
.infographic-pyisEq .decl-line strong { color: var(--ink); }
.infographic-pyisEq .diagram { display: flex; justify-content: center; align-items: flex-start; gap: 2.4rem; min-height: 130px; margin-bottom: 1.1rem; flex-wrap: wrap; }
.infographic-pyisEq .var-col { display: flex; flex-direction: column; align-items: center; }
.infographic-pyisEq .var-label {
font-family: var(--display-font); font-size: 1.05rem; font-weight: 600; color: var(--ink);
width: 32px; height: 32px; border: 1.5px solid var(--ink-soft); border-radius: 50%;
display: flex; align-items: center; justify-content: center; margin-bottom: 0.3rem;
}
.infographic-pyisEq .var-arrow { color: var(--ink-soft); font-size: 1.1rem; margin-bottom: 0.3rem; }
.infographic-pyisEq .var-box {
font-family: var(--mono-font); font-size: 0.85rem; font-weight: 700; text-align: center;
padding: 0.6rem 0.9rem; border-radius: 8px; border: 2.5px solid var(--accent); background: var(--accent-soft); color: var(--ink);
min-width: 90px;
}
.infographic-pyisEq .var-addr { font-family: var(--mono-font); font-size: 0.65rem; color: var(--ink-soft); margin-top: 0.25rem; }
.infographic-pyisEq .status-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 0.9rem; }
@media (max-width: 480px) { .infographic-pyisEq .status-grid { grid-template-columns: 1fr; } }
.infographic-pyisEq .status-card { background: var(--paper-alt); border: 1px solid var(--line); border-radius: 6px; padding: 0.55rem 0.7rem; text-align: center; font-family: var(--mono-font); font-size: 0.85rem; }
.infographic-pyisEq .status-card .badge { font-weight: 700; padding: 0.05rem 0.45rem; border-radius: 999px; margin-left: 0.35rem; }
.infographic-pyisEq .status-card .badge.t { background: var(--true-soft); color: var(--true-c); }
.infographic-pyisEq .status-card .badge.f { background: var(--false-soft); color: var(--false-c); }
.infographic-pyisEq .ie-caption { text-align: center; font-size: 0.85rem; color: var(--ink-soft); margin-bottom: 0.5rem; }
.infographic-pyisEq .ie-caption strong { color: var(--ink); }
.infographic-pyisEq .warn-note {
text-align: center; font-size: 0.78rem; color: var(--warn); background: var(--warn-soft);
border: 1px solid var(--warn); border-radius: 8px; padding: 0.55rem 0.8rem; margin-top: 0.7rem; display: none;
}
.infographic-pyisEq .warn-note.is-visible { display: block; }
@media (prefers-reduced-motion: reduce) {
.infographic-pyisEq *, .infographic-pyisEq *::before, .infographic-pyisEq *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="ie-wrap">
<h1>Object Identity: is vs ==</h1>
<p class="ie-sub">Two questions that sound similar and aren't.</p>
<div class="rule-row">
<div class="rule-card"><div class="op">==</div><div class="desc">Do they have the same value?</div></div>
<div class="rule-card"><div class="op">is</div><div class="desc">Are they the exact same object in memory?</div></div>
</div>
<div class="scenario-row" id="scenarioRow"></div>
<p class="decl-line" id="declLine"></p>
<div class="diagram" id="diagram"></div>
<div class="status-grid">
<div class="status-card">a == b <span class="badge t" id="eqBadge">True</span></div>
<div class="status-card">a is b <span class="badge t" id="isBadge">True</span></div>
</div>
<p class="ie-caption" id="ieCaption"></p>
<div class="warn-note" id="warnNote">β οΈ CPython caches small ints (-5 to 256) and interns some strings β a is b happening to be True here is an implementation detail, not something the language guarantees. Never rely on it.</div>
</div>
<script>
(function () {
var root = document.currentScript.closest('.infographic-pyisEq')
|| document.querySelector('.infographic-pyisEq');
var bodyAttr = document.body.getAttribute('data-darkmode');
var dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
var match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) root.setAttribute('data-theme', 'dark');
var ADDR_A = '0x7f3a10a0';
var ADDR_B = '0x7f3a1140';
var scenarios = [
{
key: 'same', label: 'b = a', decl: 'a = [1, 2, 3] Β· b = a',
shared: true, aVal: '[1, 2, 3]', bVal: '[1, 2, 3]', eq: true, is: true,
caption: 'b points to the exact same list as a β same value, same object. Both operators agree.'
},
{
key: 'copy', label: 'b = a.copy()', decl: 'a = [1, 2, 3] Β· b = a.copy()',
shared: false, aVal: '[1, 2, 3]', bVal: '[1, 2, 3]', eq: true, is: false,
caption: 'Same contents, different objects. == compares values (True); is compares identity (False).'
},
{
key: 'diff', label: 'b = [4, 5, 6]', decl: 'a = [1, 2, 3] Β· b = [4, 5, 6]',
shared: false, aVal: '[1, 2, 3]', bVal: '[4, 5, 6]', eq: false, is: false,
caption: 'Different values, different objects β both operators agree, and both say False.'
},
{
key: 'smallint', label: 'a, b = 5, 5', decl: 'a = 5 Β· b = 5',
shared: true, aVal: '5', bVal: '5', eq: true, is: true,
caption: 'Same small integer value β a and b happen to point to the same cached object.',
warn: true
},
{
key: 'none', label: 'a, b = None, None', decl: 'a = None Β· b = None',
shared: true, aVal: 'None', bVal: 'None', eq: true, is: true,
caption: 'None is a singleton β there is only ever one None. That\'s why "is None" is the idiomatic check.'
}
];
var scenarioRow = root.querySelector('#scenarioRow');
var declLine = root.querySelector('#declLine');
var diagram = root.querySelector('#diagram');
var eqBadge = root.querySelector('#eqBadge');
var isBadge = root.querySelector('#isBadge');
var ieCaption = root.querySelector('#ieCaption');
var warnNote = root.querySelector('#warnNote');
var currentKey = 'same';
function renderDiagram(sc) {
diagram.innerHTML = '';
if (sc.shared) {
var wrap = document.createElement('div');
wrap.style.display = 'flex';
wrap.style.flexDirection = 'column';
wrap.style.alignItems = 'center';
var arrowsRow = document.createElement('div');
arrowsRow.style.display = 'flex';
arrowsRow.style.gap = '1.8rem';
['a', 'b'].forEach(function (name) {
var col = document.createElement('div');
col.className = 'var-col';
col.innerHTML = '<span class="var-label">' + name + '</span><span class="var-arrow">β</span>';
arrowsRow.appendChild(col);
});
wrap.appendChild(arrowsRow);
var box = document.createElement('div');
box.className = 'var-box';
box.textContent = sc.aVal;
wrap.appendChild(box);
var addr = document.createElement('div');
addr.className = 'var-addr';
addr.textContent = ADDR_A;
wrap.appendChild(addr);
diagram.appendChild(wrap);
} else {
var colA = document.createElement('div');
colA.className = 'var-col';
colA.innerHTML =
'<span class="var-label">a</span><span class="var-arrow">β</span>' +
'<div class="var-box">' + sc.aVal + '</div>' +
'<div class="var-addr">' + ADDR_A + '</div>';
var colB = document.createElement('div');
colB.className = 'var-col';
colB.innerHTML =
'<span class="var-label">b</span><span class="var-arrow">β</span>' +
'<div class="var-box">' + sc.bVal + '</div>' +
'<div class="var-addr">' + ADDR_B + '</div>';
diagram.appendChild(colA);
diagram.appendChild(colB);
}
}
function render() {
var sc = scenarios.filter(function (s) { return s.key === currentKey; })[0];
declLine.innerHTML = sc.decl;
renderDiagram(sc);
eqBadge.textContent = sc.eq ? 'True' : 'False';
eqBadge.className = 'badge ' + (sc.eq ? 't' : 'f');
isBadge.textContent = sc.is ? 'True' : 'False';
isBadge.className = 'badge ' + (sc.is ? 't' : 'f');
ieCaption.innerHTML = sc.caption;
warnNote.classList.toggle('is-visible', !!sc.warn);
}
scenarios.forEach(function (sc) {
var btn = document.createElement('button');
btn.className = 'scenario-btn' + (sc.key === currentKey ? ' is-selected' : '');
btn.textContent = sc.label;
btn.addEventListener('click', function () {
root.querySelectorAll('.scenario-btn').forEach(function (b) { b.classList.remove('is-selected'); });
btn.classList.add('is-selected');
currentKey = sc.key;
render();
});
scenarioRow.appendChild(btn);
});
render();
})();
</script>
</div>