Skip to content

API Reference

Stable non-cryptographic and cryptographic hash functions for Polars.

Importing this package registers seven expression namespaces on pl.Expr: chash, nchash, bytes, geohash, h3, timehash and uuidhash. It also exports col and concat_str, which are typed wrappers around pl.col and pl.concat_str, and hash_rows, which hashes a whole row.

Examples:

>>> df = pl.DataFrame({"foo": ["hello_world"]})
>>> df.select(plh.col("foo").chash.sha2_256()).item()
'35072c1ae546350e0bfa7ab11d49dc6f129e72ccd57ec7eb671225bbd197c8f1'

The namespaces

One import registers all seven namespaces on pl.Expr. Each page below is generated from the docstrings of the namespace.

Namespace Contents
chash SHA-2, SHA-3, SHAKE128, BLAKE3 and HMAC-SHA256
nchash wyhash, xxHash, XXH3, MurmurHash3, FarmHash, CityHash, GxHash, CRC-32C, MD5 and SHA-1
bytes The bytes of a value, least or most significant byte first
geohash Geohash encode, decode and neighbors
h3 The H3 hexagonal cell index
timehash Time-bucket encode, decode and neighbors
uuidhash Deterministic UUID v5

hash_rows is a function and not a namespace. It hashes a full row, which a hash of the joined columns cannot do.

Typed wrappers

col module-attribute

col = cast(HashColumn, pl.col)

pl.col, with the polars-hash namespaces declared for a type checker.

Both functions work at run time. plh.col is a typed wrapper that declares the namespaces, so mypy and Pyright accept .chash.sha2_256() on its result. With pl.col they report an error and need a # type: ignore comment.

Examples:

>>> df = pl.DataFrame({"foo": ["hello_world"]})
>>> df.select(plh.col("foo").chash.sha2_256()).item()
'35072c1ae546350e0bfa7ab11d49dc6f129e72ccd57ec7eb671225bbd197c8f1'

concat_str module-attribute

concat_str = cast(HashConcatStr, pl.concat_str)

pl.concat_str, with the polars-hash namespaces declared for a type checker.

Use it to hash more than one column. Give a separator value: without one, ("ab", "c") and ("a", "bc") give the same hash. To hash a whole row of any type, use hash_rows instead.

The default value of ignore_nulls in pl.concat_str is False, so one null input makes the concatenation null and the hash is also null. To get a value instead, set ignore_nulls=True or replace the null values first.

Examples:

>>> df = pl.DataFrame({"foo": ["hello_world"], "bar": ["today"]})
>>> df.select(plh.concat_str("foo", "bar", separator="|").chash.sha2_256()).item()
'e65103da8dabb65a3ebd4204dbc01f0d2d5eb685a1fb039518302f9fc2fc0b73'

HExpr

Bases: Expr

A pl.Expr that declares the polars-hash namespaces.

col and concat_str return this class. Use it as the type annotation when you pass one of their expressions between functions.

Conventions

These rules apply to every expression above.

  • Elementwise. Each expression has is_elementwise=True. You can use it in select, in with_columns, in group_by(...).agg, and in streaming mode. Polars can also divide the data into chunks and change the order of operations.
  • Null values. A null input gives a null output. The expression does not hash a substitute value. hash_rows is the exception. A null is one of the values of a row, and therefore a row with a null also has a hash. The rules for the scalar arguments are different: length, key, namespace, default, len and precision must not be null, and neither may seed — except on cityhash64(), where seed=None is how you ask for the unseeded algorithm.
  • Output name. The output column has the same name as the input column. To keep both columns, use .alias(). hash_rows reads more than one column, and it keeps the name of the first, as the polars *_horizontal expressions do.
  • Object columns. Polars sends an Object column to a plugin as Binary, and it keeps no mark to identify the two. Therefore a hasher reads the eight bytes of the CPython pointer and not the value. These bytes change with each run. The digest is not repeatable, and two equal objects give two different digests. Change an Object column to a usual data type before you hash it. hash_rows rejects such a column.
  • Incorrect input type. The expression raises an error when the input type is not permitted. This occurs when Polars collects the data, not when you build the expression. All errors from the plugin become polars.exceptions.ComputeError in Python. The message starts with the plugin failed with message:.
  • Stability. The same input and the same arguments always give the same output. This does not change between polars-hash releases or Polars releases. The exception is GxHash, whose values hold within one major version of the algorithm. polars-hash pins that version, so only a release that says so can move them.