Expressions are the heart of Polars: almost every operation is written as one, and they are what the engine optimizes and parallelizes.
An expression such as pl.col("price") * 1.2 is not a result: it is a recipe describing how to compute a column. Nothing runs until you hand it to a context, a DataFrame method that evaluates expressions:
df.select(...)returns only the columns you compute.df.with_columns(...)returns all existing columns plus new or replaced ones.df.filter(...)keeps rows where a boolean expression is true.df.group_by(...).agg(...)evaluates expressions per group (next lessons).
Build expressions from pl.col("name"), literals pl.lit(5), and operators (+, *, >, &, |, ~). Methods chain: pl.col("name").str.to_uppercase(), pl.col("x").round(1), pl.col("x").cast(pl.Float32). Name the output with .alias("new"), or use keyword arguments: with_columns(total=pl.col("a") + pl.col("b")).
Expressions inside one context are independent, so Polars runs them in parallel on different cores. The flip side is that a column created in a with_columns call is not visible to other expressions in that same call; chain a second with_columns if one new column depends on another.
Because an expression is just a value, you can store it in a variable or return it from a function and reuse it across queries, which keeps pipelines short and readable.
Example
import polars as pl
df = pl.DataFrame({"item": ["tea", "cake", "jam"],
"price": [3.0, 4.5, 2.0], "qty": [2, 1, 5]})
revenue = pl.col("price") * pl.col("qty") # a reusable recipe
out = (
df.with_columns(revenue.alias("revenue"),
item=pl.col("item").str.to_uppercase())
.with_columns(big=pl.col("revenue") > 5) # needs the column above
.filter(pl.col("qty") > 1)
.select("item", "revenue", "big")
)
print(out.rows()) # [('TEA', 6.0, True), ('JAM', 10.0, True)]Remember
- An expression describes a computation; a context runs it
selectkeeps only computed columns,with_columnsadds to the frame- Expressions in one context run in parallel and can't see each other's outputs
Watch out for
- Referring to a column created earlier in the same
with_columnscall: it doesn't exist yet.