natsort
natsort produces human-expected ordering for strings containing numbers, so file2 comes before file10 instead of after it. It tokenizes values into comparable text and numeric pieces, then exposes sorted-style helpers, reusable key functions, locale-aware ordering, path ordering, real-number parsing, and index utilities. It is a sorting-key toolkit, not a semantic-version parser and not a replacement for deciding the domain-specific order your application means.
natsort is worth installing when natural ordering is user-visible and the strings are varied enough that a homegrown regex key will grow bugs. Do not use it as a semantic-version authority or assume locale-sensitive results are portable without PyICU and deployment controls.
Use it if
- You sort filenames, labels, identifiers, or table columns that contain integers or decimals embedded in text
- You need one tested implementation for signs, exponents, case handling, paths, locale, and mixed numeric values
- You want a key function compatible with list.sort, min, max, heapq, or another sorting API
- You need index-based natural ordering so several related arrays can be rearranged consistently
- You are sorting package versions by a formal scheme: the README says natsort does not actually comprehend version numbers, so packaging.version or semantic-version can enforce the rules
- Your values have a simple fixed grammar such as prefix plus integer: a short explicit key function is easier to audit and avoids a dependency
- You need identical locale ordering on every deployment but cannot install PyICU: humansorted and os_sorted can fall back to Python's process-global locale behavior with platform-dependent results
- You need official bytes support: the README says bytes are not officially supported and requires the as_utf8 helper for limited mixed cases
- You sort custom classes with unusual rich comparison behavior: the project FAQ warns that such objects are unlikely to sort correctly without an explicit key
Setup reality
pip install natsort is pure Python and the 8.4.0 metadata supports Python 3.7 and newer. The base install has no required third-party dependencies. Optional fastnumbers can speed numeric parsing, and PyICU gives humansorted and os_sorted more consistent operating-system-like locale behavior, but PyICU is a compiled extension that may require ICU development libraries when no wheel matches. Without it, natsort falls back to Python's locale module, whose collation depends on installed locales and process configuration; locale availability differs across minimal containers and operating systems. Decide first whether you need ordinary numeric token ordering, signed real-number handling, a user locale, or path semantics, because the convenience functions and ns flags make different choices. natsorted returns a new list just like sorted and does not modify its input. For in-place sorting or repeated sorts, build a key once with natsort_keygen. Natural order is not a universal specification: leading zeros, numeric types, case, accents, NaN, paths, and mixed objects can all need product-specific decisions. The library does not understand semantic-version precedence even if common version strings appear right. Pin the algorithm flags in code and add examples of your actual edge cases to tests rather than accepting whichever ordering looks plausible. If results differ between machines, inspect the generated keys and check locale and PyICU availability before blaming Python's sort, which remains stable and simply compares the keys natsort gives it.
Patterns
Sort strings by embedded numberssort-numbered-strings
from natsort import natsorted
files = ['file10.txt', 'file2.txt', 'file1.txt']
ordered = natsorted(files)
# ['file1.txt', 'file2.txt', 'file10.txt']natsorted returns a new list and leaves files unchanged, matching the behavior of Python's sorted.
Reverse natural ordersort-descending
ordered = natsorted(['v2', 'v10', 'v1'], reverse=True)reverse applies to the complete generated key; it is not a semantic-version newest-first calculation.
Recognize signed floats and exponentssort-signed-reals
from natsort import realsorted
values = ['value 5.10', 'value -3', 'value 5.2', 'value 1e2']
ordered = realsorted(values)realsorted enables signed real-number parsing; ordinary natsorted intentionally makes different sign assumptions.
Ignore letter case while sortingsort-ignore-case
from natsort import natsorted, ns
ordered = natsorted(['a10', 'A2', 'a1'], alg=ns.IGNORECASE)Python's sort is stable, so values whose normalized keys compare equal keep their original relative order.
Combine real-number and case rulescombine-algorithm-flags
from natsort import natsorted, ns
ordered = natsorted(values, alg=ns.REAL | ns.IGNORECASE)Flags are bitwise values and can be combined with |; pin the exact combination in tests because each changes tokenization.
Sort human text with locale rulessort-by-user-locale
import locale
from natsort import humansorted
locale.setlocale(locale.LC_ALL, '')
ordered = humansorted(['Z10', 'ä2', 'a1'])Results depend on the active locale and PyICU availability; set and test the deployment locale explicitly.
Approximate file-manager orderingsort-file-browser-order
import os
from natsort import os_sorted
entries = os_sorted(os.listdir('/srv/uploads'))PyICU improves matching with common file browsers; fallback locale ordering can differ across operating systems.
Natural-sort records by one fieldsort-by-object-field
from natsort import natsorted
rows = [{'name': 'rack10'}, {'name': 'rack2'}]
ordered = natsorted(rows, key=lambda row: row['name'])The key should return a supported scalar such as str, int, or float rather than relying on custom-object comparisons.
Generate a reusable in-place sort keysort-list-in-place
from natsort import natsort_keygen, ns
natural_key = natsort_keygen(alg=ns.IGNORECASE)
files.sort(key=natural_key)Create the key once when sorting repeatedly; inspecting natural_key(value) is also the best way to debug unexpected order.
Apply one natural order to related datareorder-parallel-arrays
from natsort import index_natsorted, order_by_index
labels = ['sample10', 'sample2', 'sample1']
values = [0.8, 0.4, 0.2]
index = index_natsorted(labels)
ordered_labels = order_by_index(labels, index)
ordered_values = order_by_index(values, index)Keep the index tied to the exact input length and order; changing either array before applying it misaligns the data.
Sort numbers and numeric strings togethersort-mixed-numbers-text
from natsort import natsorted
ordered = natsorted([4.5, '10', 2, 'item3'])Mixed types are supported, but define expected placement for nonnumeric text in tests rather than assuming a universal human order.
Adapt UTF-8 bytes for natural sortingsort-utf8-bytes
from natsort import as_utf8, natsorted
ordered = natsorted([b'a40', b'a6'], key=as_utf8)bytes are not officially supported; this helper is appropriate only when the values are valid UTF-8 and the limitations are acceptable.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| packaging | PyPI | You sort PEP 440 Python package versions and need formal version precedence |
| semantic-version | PyPI | You need Semantic Versioning parsing, validation, ranges, and precedence |
| looseversion | PyPI | You are replacing the removed distutils LooseVersion behavior for loosely structured versions |