string.capwords()'s sep Argument Disables Whitespace Splitting (tested)
string.capwords() looks like str.title() with saner apostrophe handling: split into words, capitalize each, rejoin. We measured its optional sep argument, and it does something sharper than just changing the joining character -- it changes what counts as a word boundary at all.
1. capwords() collapses repeated whitespace; title() preserves it
import string
print(repr(string.capwords("hello world")))
print(repr("hello world".title()))
'Hello World'
'Hello World'
Measured: capwords() splits on whitespace with str.split() (no argument, so it collapses runs of spaces/tabs/newlines) and rejoins with a single space by default -- the original spacing is gone. str.title() walks the string character by character and never touches whitespace, so the original spacing survives exactly. If you need to preserve formatting (e.g. a multi-line address field), capwords() silently normalizes it away.
2. capwords() handles apostrophes better than title() -- but only without a custom sep
import string
print(repr(string.capwords("it's a test-case")))
print(repr("it's a test-case".title()))
"It's A Test-case"
"It'S A Test-Case"
Measured: str.title() treats the apostrophe as a word boundary and capitalizes the letter after it, producing the well-known It'S bug, and it also capitalizes after the hyphen (Test-Case). capwords() only splits on whitespace, so it's stays intact and test-case is left as one capitalized word, Test-case. This is the behavior most people actually want from "title case."
3. Passing sep stops capwords() from treating spaces as word boundaries too
import string
print(repr(string.capwords("mcdonald new-york", sep="-")))
'Mcdonald new-York'
Measured: with sep="-", capwords() calls "mcdonald new-york".split("-"), which gives exactly two pieces: "mcdonald new" and "york". Only the first letter of each piece gets capitalized -- so "mcdonald new" becomes "Mcdonald new" with new left lowercase, since there's no space-splitting happening inside that piece at all. The result looks like a partial capitalization bug, but it's working exactly as specified: once you pass sep, that character is the only word boundary considered, and whitespace inside a chunk is just more text. If you want both space- and hyphen-separated words capitalized, split on both yourself rather than relying on a single sep value.
Frequently asked questions
Does string.capwords() preserve the original spacing in the input?
No -- we measured this: capwords() splits with str.split() (which collapses any run of whitespace) and rejoins with a single space, so 'hello world' becomes 'hello world'. str.title() doesn't touch whitespace at all, so it preserves the original spacing exactly.
Is string.capwords() better than str.title() for names with apostrophes?
Yes, for the common case -- we confirmed str.title() produces "It'S" from "it's" because it treats the apostrophe as a word boundary, while capwords() (which only splits on whitespace by default) leaves "it's" intact as one word.
Why does string.capwords(text, sep='-') only capitalize some words?
We measured this directly: passing sep makes that character the only word boundary considered. 'mcdonald new-york' splits on '-' into 'mcdonald new' and 'york' -- the space inside the first piece is never treated as a boundary, so only 'mcdonald' gets capitalized, not 'new'.
How do I title-case text that has both spaces and hyphens as word separators?
string.capwords() only recognizes one separator at a time. Based on what we measured, you'd need to split the text yourself (e.g. with a regex on [ -]) and capitalize each piece, since neither capwords() with a single sep nor str.title() alone handles mixed separators the way you'd want.
What word-splitting rule does string.capwords() use by default?
With no sep argument, we confirmed it uses str.split() with no arguments, which splits on any whitespace and discards empty strings from repeated whitespace -- the same rule that makes it collapse multiple spaces into one in the output.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in string module: compared string.capwords() against str.title() on text with repeated spaces and an apostrophe, then called string.capwords() with a custom sep argument on text that mixes spaces and the separator character. PlainHeaders is our extension; Python's string module is built in.