difflib quick_ratio() Returns 1.0 for Completely Reordered Strings (tested)

difflib.SequenceMatcher has three similarity methods: ratio(), quick_ratio(), and real_quick_ratio(). We measured all three on the same pair of strings and the fast ones gave an answer nowhere close to the real one.

1. A reversed string looks like a perfect match

import difflib

a = "abcdefgh"
b = "hgfedcba"

sm = difflib.SequenceMatcher(None, a, b)
print("ratio():           ", sm.ratio())
print("quick_ratio():      ", sm.quick_ratio())
print("real_quick_ratio():", sm.real_quick_ratio())
ratio():            0.125
quick_ratio():       1.0
real_quick_ratio():  1.0

Measured: a and b are each other reversed -- about as different in structure as two 8-character strings can be while sharing every character. The real ratio() correctly scores them as mostly dissimilar (0.125). quick_ratio() and real_quick_ratio() both report a perfect 1.0, with no hint that this is an estimate rather than the actual score.

2. Why: they only count characters, not order

import collections

print(collections.Counter(a) == collections.Counter(b))
True

Measured: quick_ratio() computes its score from element multiset overlap alone -- how many characters the two strings have in common, regardless of position. Since a and b contain exactly the same letters, it scores them as identical. It never looks at alignment or sequence at all, which is exactly what ratio() spends its time doing.

3. This is by design -- they're upper-bound filters, not approximations

results = difflib.get_close_matches("abcdefgh", ["hgfedcba", "abcdefgh", "zzzzzzzz"], n=3, cutoff=0.0)
print(results)
['abcdefgh', 'hgfedcba', 'zzzzzzzz']

Measured: get_close_matches() uses real_quick_ratio() and quick_ratio() internally as cheap upper bounds to skip obviously-bad candidates before running the expensive real ratio() -- a candidate is only discarded early if even its inflated quick score falls below the cutoff. They are guaranteed to be >= ratio(), never lower, which makes them safe as a pre-filter but wrong if read as a similarity score on their own.

4. Fix: always call ratio() for an actual similarity score

def similarity(a, b):
    return difflib.SequenceMatcher(None, a, b).ratio()

print(similarity("abcdefgh", "hgfedcba"))
0.125

Measured: only ratio() accounts for the actual alignment between the two sequences. Use quick_ratio()/real_quick_ratio() only to short-circuit a large batch comparison before falling back to ratio() for the real number -- never as the reported score itself.

Frequently asked questions

Does quick_ratio() approximate SequenceMatcher.ratio()?

No -- we measured it returning 1.0 for two strings that are exact reverses of each other, where the real ratio() was 0.125. quick_ratio() ignores character order entirely.

What does quick_ratio() actually measure?

We confirmed it scores based only on how many characters the two sequences have in common as a multiset (via collections.Counter-style overlap), with no regard for position or alignment.

Is quick_ratio() always higher than ratio()?

Yes -- by design it's an upper bound. We measured it equal to or greater than ratio() in every case tested; it's meant to let get_close_matches() cheaply reject bad candidates before computing the real ratio().

Should I use quick_ratio() for fuzzy string matching?

Not as the final score -- we measured it giving a perfect-looking 1.0 for strings that are actually very dissimilar once order matters. Use ratio() for the real number; quick_ratio() is only safe as an internal pre-filter.

Does get_close_matches use quick_ratio() instead of ratio()?

It uses quick_ratio() and real_quick_ratio() first to skip clearly-bad candidates, but we confirmed it still falls back to the real ratio() for anything that passes those cheap checks, so its final results are correct even though the shortcut methods alone are not.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in difflib: compared SequenceMatcher.ratio() against its quick_ratio() and real_quick_ratio() on pairs of strings that share the same characters but in a different order. PlainHeaders is our extension; Python's difflib module is built in.