π₯ First-Class Functions
In Python, functions are first-class objects. This means a function can be treated like any other value.
A function can be:
Stored in a variable
Passed as an argument
Returned from another function
Stored in a list, tuple, or dictionary
1οΈβ£ Store a Function in a Variable
def greet():
print("Hello!")
message = greet
message() #Hello!Here, message refers to the greet function.
2οΈβ£ Pass a Function as an Argument
A function can be passed to another function.
def greet():
print("Hello!")
def execute(function):
function()
execute(greet) #Hello!Here, greet is passed as an argument to execute().
3οΈβ£ Return a Function
A function can also return another function.
def outer():
def inner():
print("Hello!")
return inner
result = outer()
result() #Hello!4οΈβ£ Store Functions in a List
Functions can even be stored inside a list.
def add():
print("Adding")
def subtract():
print("Subtracting")
operations = [add, subtract]
operations[0]() #Adding
operations[1]() #Subtractingβ Why is this Important?
First-class functions are the foundation for concepts such as:
πΉ Higher-Order Functions
πΉ Lambda Functions
πΉ Decorators
πΉ Callbacks
πΉ Functional Programmingπ§ Remember
First-Class Function = A function can be treated like a normal values.
<div class="infographic-pyfirstclass">
<style>
.infographic-pyfirstclass {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--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: 800px;
margin: 0 auto;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.infographic-pyfirstclass[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-pyfirstclass *, .infographic-pyfirstclass *::before, .infographic-pyfirstclass *::after { box-sizing: border-box; }
.infographic-pyfirstclass .fc-wrap { padding: 0 clamp(1rem, 4vw, 2rem) 1.5rem; }
.infographic-pyfirstclass 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-pyfirstclass .fc-sub { text-align: center; color: var(--ink-soft); font-size: 0.86rem; margin: 0 0 1.4rem; }
.infographic-pyfirstclass .fc-tabs { display: flex; justify-content: center; gap: 0.35rem; margin-bottom: 1.4rem; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.infographic-pyfirstclass .fc-tab-btn {
font: inherit; font-family: var(--mono-font); font-size: 0.75rem; font-weight: 700;
background: none; border: none; border-bottom: 2.5px solid transparent; color: var(--ink-soft);
padding: 0.5rem 0.65rem; cursor: pointer; margin-bottom: -1px;
}
.infographic-pyfirstclass .fc-tab-btn.is-active { color: var(--accent); border-bottom-color: var(--accent); }
.infographic-pyfirstclass .fc-panel.is-hidden-tab { display: none; }
.infographic-pyfirstclass .code-line {
font-family: var(--mono-font); font-size: 0.82rem; text-align: center; color: var(--ink-soft);
background: var(--paper-alt); border: 1px solid var(--line); border-radius: 8px;
padding: 0.7rem 0.8rem; margin-bottom: 1rem; line-height: 1.7;
}
.infographic-pyfirstclass .code-line strong { color: var(--ink); }
/* memory box (tab 1) */
.infographic-pyfirstclass .diagram { display: flex; flex-direction: column; align-items: center; margin-bottom: 1rem; }
.infographic-pyfirstclass .arrows-row { display: flex; gap: 1.8rem; }
.infographic-pyfirstclass .var-col { display: flex; flex-direction: column; align-items: center; }
.infographic-pyfirstclass .var-label {
font-family: var(--display-font); font-size: 0.95rem; font-weight: 600; color: var(--ink);
padding: 0.2rem 0.6rem; border: 1.5px solid var(--ink-soft); border-radius: 999px; margin-bottom: 0.3rem;
}
.infographic-pyfirstclass .var-arrow { color: var(--ink-soft); font-size: 1.1rem; }
.infographic-pyfirstclass .fn-box {
margin-top: 0.3rem; font-family: var(--mono-font); font-size: 0.85rem; font-weight: 700;
padding: 0.6rem 1rem; border-radius: 8px; border: 2.5px solid var(--accent); background: var(--accent-soft); color: var(--accent);
}
/* generic controls */
.infographic-pyfirstclass .ctl-row { display: flex; justify-content: center; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; align-items: center; }
.infographic-pyfirstclass .toggle-btn, .infographic-pyfirstclass .dict-key-btn {
font: inherit; font-family: var(--mono-font); font-size: 0.8rem; font-weight: 700;
background: var(--paper-alt); border: 1.5px solid var(--line); color: var(--ink-soft);
padding: 0.4rem 0.75rem; cursor: pointer; border-radius: 6px;
}
.infographic-pyfirstclass .toggle-btn.is-selected, .infographic-pyfirstclass .dict-key-btn.is-selected {
border-color: var(--accent); color: var(--accent); background: var(--accent-soft);
}
.infographic-pyfirstclass .ctl-row input {
font-family: var(--mono-font); font-size: 0.85rem; padding: 0.4rem 0.55rem;
border: 1.5px solid var(--line); border-radius: 5px; background: var(--paper-alt); color: var(--ink); width: 90px;
text-align: center;
}
.infographic-pyfirstclass .ctl-row input:focus { outline: none; border-color: var(--accent); }
.infographic-pyfirstclass .run-btn {
font: inherit; font-family: var(--mono-font); font-size: 0.82rem; font-weight: 700;
background: var(--accent); color: #fff; border: none; border-radius: 999px;
padding: 0.5rem 1.1rem; cursor: pointer;
}
/* result readouts */
.infographic-pyfirstclass .result-line {
text-align: center; font-family: var(--mono-font); font-size: 0.95rem; font-weight: 700; color: var(--accent);
margin-bottom: 0.4rem; min-height: 1.3em;
}
.infographic-pyfirstclass .fc-caption { text-align: center; font-size: 0.85rem; color: var(--ink-soft); }
/* factory chips (tab 3) */
.infographic-pyfirstclass .factory-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem; margin-bottom: 1rem; }
.infographic-pyfirstclass .factory-chip {
border: 1.5px solid var(--accent); background: var(--accent-soft); border-radius: 8px; padding: 0.55rem 0.7rem;
display: flex; flex-direction: column; align-items: center; gap: 0.35rem; min-width: 130px;
}
.infographic-pyfirstclass .factory-name { font-family: var(--mono-font); font-size: 0.8rem; font-weight: 700; color: var(--accent); }
.infographic-pyfirstclass .factory-test { display: flex; gap: 0.3rem; align-items: center; }
.infographic-pyfirstclass .factory-test input {
width: 46px; font-family: var(--mono-font); font-size: 0.78rem; text-align: center;
padding: 0.25rem; border: 1px solid var(--line); border-radius: 4px; background: var(--paper); color: var(--ink);
}
.infographic-pyfirstclass .factory-test button {
font: inherit; font-family: var(--mono-font); font-size: 0.72rem; font-weight: 700;
background: var(--accent); color: #fff; border: none; border-radius: 4px; padding: 0.25rem 0.5rem; cursor: pointer;
}
.infographic-pyfirstclass .factory-result { font-family: var(--mono-font); font-size: 0.75rem; color: var(--ink-soft); min-height: 1.2em; }
/* dict picker (tab 4) */
.infographic-pyfirstclass .dict-display {
text-align: center; font-family: var(--mono-font); font-size: 0.8rem; color: var(--ink-soft); margin-bottom: 0.9rem;
}
@media (prefers-reduced-motion: reduce) {
.infographic-pyfirstclass *, .infographic-pyfirstclass *::before, .infographic-pyfirstclass *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="fc-wrap">
<h1>First-Class Functions</h1>
<p class="fc-sub">In Python, a function is just another value β assign it, pass it, return it, store it.</p>
<div class="fc-tabs">
<button class="fc-tab-btn is-active" data-tab="assign">Assign</button>
<button class="fc-tab-btn" data-tab="pass">Pass In</button>
<button class="fc-tab-btn" data-tab="return">Return Out</button>
<button class="fc-tab-btn" data-tab="store">Store in a Dict</button>
</div>
<!-- TAB 1: ASSIGN -->
<div class="fc-panel" id="tabAssign">
<div class="code-line">def greet(): <strong>return "Hi!"</strong><br>say_hi = greet</div>
<div class="diagram">
<div class="arrows-row">
<div class="var-col"><span class="var-label">greet</span><span class="var-arrow">β</span></div>
<div class="var-col"><span class="var-label">say_hi</span><span class="var-arrow">β</span></div>
</div>
<div class="fn-box">function greet</div>
</div>
<div class="ctl-row"><button class="run-btn" id="assignRunBtn">Run: say_hi()</button></div>
<p class="result-line" id="assignResult"></p>
<p class="fc-caption">say_hi isn't a copy β it's another name for the exact same function object.</p>
</div>
<!-- TAB 2: PASS AS ARGUMENT -->
<div class="fc-panel is-hidden-tab" id="tabPass">
<div class="code-line">
def shout(t): <strong>return t.upper() + "!"</strong><br>
def whisper(t): <strong>return t.lower() + "..."</strong><br>
def greet_loud(func, name): <strong>return func(name)</strong>
</div>
<div class="ctl-row">
<button class="toggle-btn is-selected" data-fn="shout">shout</button>
<button class="toggle-btn" data-fn="whisper">whisper</button>
<input id="passNameInput" type="text" value="Alice" />
</div>
<div class="ctl-row"><button class="run-btn" id="passRunBtn">Run: greet_loud(shout, "Alice")</button></div>
<p class="result-line" id="passResult"></p>
<p class="fc-caption">greet_loud doesn't care which function you hand it β it just calls func(name).</p>
</div>
<!-- TAB 3: RETURN A FUNCTION -->
<div class="fc-panel is-hidden-tab" id="tabReturn">
<div class="code-line">
def make_multiplier(n):<br>
def multiply(x): <strong>return x * n</strong><br>
return multiply
</div>
<div class="ctl-row">
<input id="factoryN" type="text" value="3" style="width:60px" />
<button class="run-btn" id="factoryCreateBtn">Create times_n = make_multiplier(n)</button>
</div>
<div class="factory-row" id="factoryRow"></div>
<p class="fc-caption">Each function this creates remembers its own n β that's a closure.</p>
</div>
<!-- TAB 4: STORE IN A DICT -->
<div class="fc-panel is-hidden-tab" id="tabStore">
<div class="dict-display">operations = {"add": add, "sub": sub, "mul": mul, "div": div}</div>
<div class="ctl-row" id="opKeyRow"></div>
<div class="ctl-row">
<input id="storeX" type="text" value="6" />
<span style="font-family:var(--mono-font); color:var(--ink-soft);">and</span>
<input id="storeY" type="text" value="3" />
</div>
<div class="ctl-row"><button class="run-btn" id="storeRunBtn">Run: operations["add"](6, 3)</button></div>
<p class="result-line" id="storeResult"></p>
<p class="fc-caption">The dict holds the functions themselves β operations[key] fetches one, then (...) calls it.</p>
</div>
</div>
<script>
(function () {
var root = document.currentScript.closest('.infographic-pyfirstclass')
|| document.querySelector('.infographic-pyfirstclass');
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');
/* ---------------- tabs ---------------- */
var tabBtns = root.querySelectorAll('.fc-tab-btn');
var panels = {
assign: root.querySelector('#tabAssign'),
pass: root.querySelector('#tabPass'),
return: root.querySelector('#tabReturn'),
store: root.querySelector('#tabStore')
};
tabBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
tabBtns.forEach(function (b) { b.classList.toggle('is-active', b === btn); });
var target = btn.dataset.tab;
Object.keys(panels).forEach(function (key) {
panels[key].classList.toggle('is-hidden-tab', key !== target);
});
});
});
/* ---------------- TAB 1: assign ---------------- */
root.querySelector('#assignRunBtn').addEventListener('click', function () {
root.querySelector('#assignResult').innerHTML = 'say_hi() β "Hi!" Β· say_hi is greet β True';
});
/* ---------------- TAB 2: pass as argument ---------------- */
var passFnBtns = root.querySelectorAll('#tabPass .toggle-btn');
var passNameInput = root.querySelector('#passNameInput');
var passRunBtn = root.querySelector('#passRunBtn');
var passResult = root.querySelector('#passResult');
var currentFn = 'shout';
function updatePassBtn() {
passRunBtn.textContent = 'Run: greet_loud(' + currentFn + ', "' + (passNameInput.value || '') + '")';
}
passFnBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
passFnBtns.forEach(function (b) { b.classList.toggle('is-selected', b === btn); });
currentFn = btn.dataset.fn;
updatePassBtn();
});
});
passNameInput.addEventListener('input', updatePassBtn);
updatePassBtn();
passRunBtn.addEventListener('click', function () {
var name = passNameInput.value || '';
var out = currentFn === 'shout' ? (name.toUpperCase() + '!') : (name.toLowerCase() + '...');
passResult.textContent = 'greet_loud(' + currentFn + ', "' + name + '") β "' + out + '"';
});
/* ---------------- TAB 3: return a function (closures) ---------------- */
var factoryRow = root.querySelector('#factoryRow');
var factoryN = root.querySelector('#factoryN');
var factoryCount = 0;
root.querySelector('#factoryCreateBtn').addEventListener('click', function () {
var n = parseFloat(factoryN.value);
if (isNaN(n)) return;
if (factoryRow.children.length >= 3) factoryRow.removeChild(factoryRow.firstChild);
var chip = document.createElement('div');
chip.className = 'factory-chip';
var idSuffix = 'f' + (++factoryCount);
chip.innerHTML =
'<div class="factory-name">times_' + n + ' = make_multiplier(' + n + ')</div>' +
'<div class="factory-test">' +
'<span style="font-family:var(--mono-font); font-size:0.78rem; color:var(--ink-soft);">x =</span>' +
'<input type="text" value="4" id="in-' + idSuffix + '" />' +
'<button id="btn-' + idSuffix + '">call</button>' +
'</div>' +
'<div class="factory-result" id="res-' + idSuffix + '"></div>';
factoryRow.appendChild(chip);
var xInput = chip.querySelector('#in-' + idSuffix);
var callBtn = chip.querySelector('#btn-' + idSuffix);
var resEl = chip.querySelector('#res-' + idSuffix);
callBtn.addEventListener('click', function () {
var x = parseFloat(xInput.value);
if (isNaN(x)) return;
resEl.textContent = 'times_' + n + '(' + x + ') β ' + (x * n);
});
});
/* ---------------- TAB 4: store in a dict ---------------- */
var ops = {
add: function (a, b) { return a + b; },
sub: function (a, b) { return a - b; },
mul: function (a, b) { return a * b; },
div: function (a, b) { return b === 0 ? null : a / b; }
};
var opKeyRow = root.querySelector('#opKeyRow');
var storeX = root.querySelector('#storeX');
var storeY = root.querySelector('#storeY');
var storeRunBtn = root.querySelector('#storeRunBtn');
var storeResult = root.querySelector('#storeResult');
var currentOpKey = 'add';
Object.keys(ops).forEach(function (key) {
var btn = document.createElement('button');
btn.className = 'dict-key-btn' + (key === currentOpKey ? ' is-selected' : '');
btn.textContent = '"' + key + '"';
btn.addEventListener('click', function () {
root.querySelectorAll('#opKeyRow .dict-key-btn').forEach(function (b) { b.classList.remove('is-selected'); });
btn.classList.add('is-selected');
currentOpKey = key;
updateStoreBtn();
});
opKeyRow.appendChild(btn);
});
function updateStoreBtn() {
storeRunBtn.textContent = 'Run: operations["' + currentOpKey + '"](' + (storeX.value || 0) + ', ' + (storeY.value || 0) + ')';
}
storeX.addEventListener('input', updateStoreBtn);
storeY.addEventListener('input', updateStoreBtn);
updateStoreBtn();
storeRunBtn.addEventListener('click', function () {
var x = parseFloat(storeX.value) || 0;
var y = parseFloat(storeY.value) || 0;
var fn = ops[currentOpKey];
var out = fn(x, y);
storeResult.textContent = 'operations["' + currentOpKey + '"](' + x + ', ' + y + ') β ' + (out === null ? 'ZeroDivisionError' : out);
});
})();
</script>
</div>