That’s not “the last digit” of the number. That’s the last digit of the string str
gave you when passed the number.
When you call str
on a float, Python gives you enough digits that calling float
on the string will give you the original float. For this purpose, a trailing 1 or 9 is less likely to be necessary than other digits, because a trailing 1 or 9 means the number is very close to the value you’d get by rounding off that digit. There’s a good chance no other floats are closer, and if so, that digit can be discarded without sacrificing float(str(original_float))
behavior.
If str
gave you enough digits to exactly represent the argument, the last digit would almost always be 5, except when random.random()
returns 0.0, in which case the last digit would be 0. (Floats can only represent dyadic rationals, and the last nonzero decimal digit of a non-integer dyadic rational is always 5.) The outputs would also be extremely long, looking like
>>> import decimal, random
>>> print(decimal.Decimal(random.random()))
0.29711195452007921335990658917580731213092803955078125
which is one of the reasons str
doesn’t do that.
If str
gave you exactly 17 significant digits (enough to distinguish all float values from each other, but sometimes more digits than necessary), then the effect you’re seeing would disappear. There would be a nearly uniform distribution of trailing digits (including 0).
(Also, you forgot that str
sometimes returns a string in scientific notation, but that’s a minor effect, because there’s a low probability of getting a float where that would happen out of random.random()
.)