If you can reseed the random generator, your approach is fine and secure, but very inefficient. You're reinventing the proverbial wheel.
Python 3's random module uses the Mersenne Twister which has a period of 2^19937. It's not a CSPRNG so can be predicted, but that requires 624 consecutive 32 bit integers of output due to it's huge internal state. That's 19968 bits. You're only using 256 of them. That still leaves 19712 bits of security against prediction. If you adhered to 256 bits of security, you should be able to generate 77 such keys and still remain very secure against predicting the 78th. You would of course have to reseed the generator with a corresponding 256 bits of entropy to generate a single fully random key. Otherwise your seed material is diluted across all keys, creating keys with only 78 bits of entropy in them (for a 256 bit seed).
This leads to using the OS inbuilt generator to self seed random(). Python can use /dev/urandom for this (or CryptGenRandom probably). The inefficiency mentioned earlier is that you might as well dispense with Python's random number generator and use bits from /dev/urandom directly. Or use Python's secrets module and keep the whole thing in house via an OS /CSPRNG combination.
So in a way, Mr Antonopoulos was right in his book, but your bit banging method will work too. It's just a tad circuitous.
It then becomes somewhat of a dialectic as to what the true entropy content is of keys generated via /dev/urandom.
fill up each index with a random number
That's not writing your own generator, but using an existing one. (Depending on it's properties, it might be ok to just collect bits and use them together, or it might be not. Likely, it's not ok.) $\endgroup$