The First Class Function
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- L4
- Asked in
- Horizon Media
Problem
Implement first_class_demo(test_cases), where test_cases is a list of dicts. Each dict has an op of either 'apply_twice' or 'compose' and an integer x. Inside, build a registry of named one-argument functions: 'double' = x*2, 'inc' = x+1, 'square' = x*x. For an 'apply_twice' op, look up the named function in f and return f(f(x)). For a 'compose' op, look up f and g, build the composed function lambda x: f(g(x)) (apply g first, then f), and apply it to x. Return the list of results, one per test case, in the same order as the input. Your implementation should pass functions as values and return a function from compose (closure). An empty test_cases returns an empty list.
Functions travel as values - prove you can pass one around.
Example 1
Input:
test_cases = [{"f":"double","x":3,"op":"apply_twice"},{"f":"double","g":"inc","x":5,"op":"compose"}]Output:
[12,12]
Example 2
Input:
test_cases = [{"f":"inc","x":10,"op":"apply_twice"},{"f":"square","g":"inc","x":4,"op":"compose"},{"f":"double","g":"double","x":7,"op":"compose"}]Output:
[12,25,28]
Worked solution and explanation
Why this problem exists in real interviews
This tests understanding of first-class functions and function composition in Python. It probes whether a candidate can pass functions as arguments, return functions from functions, and chain transformations. The driver first_class_demo ties it together: it builds a registry of named functions and dispatches each test case through apply_twice or compose.
Break down the requirements
Step 1: Build the function registry
Map each name to a one-argument function: 'double' -> x*2, 'inc' -> x+1, 'square' -> x*x. These are the first-class values you will pass around.
Step 2: Implement apply_twice(f, x)
Call f(x) to get an intermediate result, then call f on that result and return it: f(f(x)).
Step 3: Implement compose(f, g)
Return a new function that, when called with x, computes f(g(x)) - apply g first, then f. This closure captures f and g.
Step 4: Dispatch each test case
Iterate the test cases in order. For 'apply_twice', look up f and return apply_twice(f, x). For 'compose', look up f and g, build compose(f, g), and apply it to x. Collect each result into a list and return it.
The solution
def first_class_demo(test_cases):
registry = {
'double': lambda x: x * 2,
'inc': lambda x: x + 1,
'square': lambda x: x * x,
}
def apply_twice(f, x):
first = f(x)
result = f(first)
return result
def compose(f, g):
def composed(x):
inner = g(x)
result = f(inner)
return result
return composed
results = []
for case in test_cases:
op = case['op']
x = case['x']
if op == 'apply_twice':
f = registry[case['f']]
results.append(apply_twice(f, x))
elif op == 'compose':
f = registry[case['f']]
g = registry[case['g']]
composed = compose(f, g)
results.append(composed(x))
return resultsCommon follow-up questions
- How would you compose an arbitrary number of functions? (Tests `functools.reduce` with a compose helper or a loop.)
- What is the difference between a closure and a class with __call__? (Tests understanding of two ways to create callable objects.)
- How does this relate to decorators? (Tests that decorators are syntactic sugar for function wrapping, which is a form of composition.)