statistics: A Wrong xbar Silently Corrupts variance() (tested)

statistics.variance() and stdev() accept an optional precomputed mean as a performance shortcut, so callers who already know the mean don't pay to recompute it. We measured what happens when that precomputed value is wrong.

1. A wrong xbar produces a wrong result with no error, warning, or validation

import statistics as st

data = [1, 2, 3, 4, 5]

print(st.mean(data))
print(st.variance(data))
print(st.variance(data, xbar=100))
3
2.5
11763.75

Measured: the real mean of data is 3, and variance() correctly computed without xbar returns 2.5. Passing a deliberately wrong xbar=100 doesn't raise StatisticsError, doesn't warn, and doesn't check the value against the data at all -- it just computes the sum of squared deviations from the wrong center and returns 11763.75 as if it were correct.

2. stdev() has the same gap, and it compounds through the square root

import statistics as st

data = [1, 2, 3, 4, 5]

print(st.stdev(data))
print(st.stdev(data, xbar=100))
1.5811388300841898
108.46082241989501

Measured: stdev() takes the same unchecked xbar shortcut and returns 108.46 instead of the correct 1.58 -- nearly 70x too large, with no indication anything is wrong. A caching bug that stores a stale mean (for example, recomputing a running mean after new data arrives but forgetting to refresh a cached value passed into variance()) produces silently wrong variance/stdev numbers that look like plausible floats, not an exception to catch.

3. The population variants use a different keyword name, mu, not xbar

import statistics as st

data = [1, 2, 3, 4, 5]

print(st.pvariance(data, mu=100))

try:
    st.pvariance(data, xbar=100)
except TypeError as e:
    print("pvariance(xbar=...) raised:", e)
9411
pvariance(xbar=...) raised: pvariance() got an unexpected keyword argument 'xbar'

Measured: pvariance()/pstdev() (the population variants) accept the same kind of precomputed-center shortcut, but under the keyword mu instead of xbar -- reusing xbar from a variance() call raises a plain TypeError for the wrong keyword name, which is at least loud, but the mu value itself gets exactly the same lack of validation as xbar once you use the right name.

Frequently asked questions

Does statistics.variance() check that a passed xbar value is correct?

No -- we measured variance([1,2,3,4,5], xbar=100) returning 11763.75 with no error or warning, instead of the correct 2.5. The xbar parameter is a performance shortcut with no validation against the actual data.

What happens if you pass the wrong precomputed mean to stdev()?

It silently returns a wrong result -- we measured stdev([1,2,3,4,5], xbar=100) returning 108.46, about 70 times larger than the correct 1.58, with no exception raised.

Is the precomputed-mean parameter named xbar or mu in Python's statistics module?

Both, depending on the function -- we measured variance() and stdev() using xbar, while pvariance() and pstdev() (the population variants) use mu. Passing xbar to pvariance() raises a TypeError for the unexpected keyword.

How do I safely use the xbar shortcut in statistics.variance()?

Only pass it when you're certain it's the current, correct mean of the exact data being passed -- we measured no runtime check at all, so a stale or wrong value produces a plausible-looking but incorrect float instead of an error you could catch.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in statistics module: called variance(), stdev(), and pvariance() with a deliberately wrong precomputed mean passed via their xbar/mu keyword argument. PlainHeaders is our extension; Python's statistics module is built in.