A valuation with visible dependencies
Suppose a fictional portfolio holds two units priced at USD 100 each and three units priced at USD 50 each. The position values are USD 200 and USD 150, giving a total of USD 350. There are no fees, cash balances or currency conversions in this example.
(quantity, price_in_usd). One function values a position; another combines that calculation with a sum.def position_value(position: tuple[int, int]) -> int:
"""Return USD value for a (quantity, USD unit price) pair."""
quantity, price = position
return quantity * price
def portfolio_value(positions: tuple[tuple[int, int], ...]) -> int:
"""Sum position values without changing the input positions."""
return sum(map(position_value, positions))
positions = ((2, 100), (3, 50))
values = tuple(map(position_value, positions))
print(values)
# (200, 150)
print(portfolio_value(positions))
# 350
print(positions)
# ((2, 100), (3, 50))position_value is pure for the stated integer-pair inputs: its result depends on the supplied pair, and it changes no externally visible state. The same is true of portfolio_value for a tuple of these pairs. The printing happens afterward, outside the calculations.map is a higher-order function: it accepts another function as an argument. It returns an iterator that applies that function to the input elements; tuple collects the individual values, while sum aggregates them. See the official map reference. A comprehension would also be a reasonable way to express this calculation.Put changing information at the boundary
prices dictionary has a dependency its call does not reveal. A function that fetches a live quote can return a different number even when its explicit arguments are unchanged. A function that updates a shared positions dictionary can also change what the next calculation sees.A useful design is to load and validate a market snapshot first, pass it into the calculation, then save or display the returned result. Real applications need these effects; keeping them at a clear boundary helps isolate numerical logic. For research reproducibility, retain the input snapshot, configuration and code/environment versions as well. A pure calculation cannot recover yesterday's missing market data.
What the syntax does not guarantee
map or a lambda does not make a calculation pure. The function passed to map can still mutate an object; a lambda can still read a changing global. Python describes lambda expressions as small function expressions, with access to surrounding names, in its lambda tutorial.Sources
- Python 3.14: Functional Programming HOWTO — functional style, purity and Python's support for several programming approaches.
- Python 3.14: Built-in functions,
map— applying a supplied function through an iterator. - Python 3.14: Lambda expressions — anonymous function expressions and access to surrounding names.
- Python 3.14: Objects, values and types — mutability and references inside immutable containers.