Fastest Deterministic Method
import random
import binascii
e = random.Random(seed)
binascii.b2a_base64(random.getrandbits(48).to_bytes(6, 'little'), newline=False)
Fastest System Random Method
import os
import binascii
binascii.b2a_base64(os.urandom(6), newline=False)
Url Safe Methods
Use os.urandom
import os
import base64
base64.urlsafe_b64encode(os.urandom(6)).decode()
Use random.Random.choices (slow, but flexible)
import random
import string
alphabet = string.ascii_letters + string.digits + '-_'
''.join(random.choices(alphabet, k=8))
Use random.Random.getrandbits (faster than random.Random.randbytes)
import random
import base64
base64.urlsafe_b64encode(random.getrandbits(48).to_bytes(6, 'little')).decode()
Use random.Random.randbytes (python >= 3.9)
import random
import base64
base64.urlsafe_b64encode(random.randbytes(6)).decode()
Use random.SystemRandom.randbytes (python >= 3.9)
import random
import base64
e = random.SystemRandom()
base64.urlsafe_b64encode(e.randbytes(6)).decode()
random.SystemRandom.getrandbits is not recommended if python >= 3.9, since it takes 2.5x time comparing to random.SystemRandom.randbytes and is more complicated.
Use secrets.token_bytes (python >= 3.6)
import secrets
import base64
base64.urlsafe_b64encode(secrets.token_bytes(6)).decode()
Use secrets.token_urlsafe (python >= 3.6)
import secrets
secrets.token_urlsafe(6) # 6 byte base64 has 8 char
Further Discussion
secrets.token_urlsafe implementation in python3.9
tok = token_bytes(nbytes)
base64.urlsafe_b64encode(tok).rstrip(b'=').decode('ascii')
Since ASCII bytes .decode() is faster than .decode('ascii'),
and .rstrip(b'=') is useless when nbytes % 6 == 0.
base64.urlsafe_b64encode(secrets.token_bytes(nbytes)).decode() is faster (~20%).
On Windows10, bytes based method is 2x faster when nbytes=6(8 char), and 5x faster when nbytes=24(32 char).
On Windows 10(my laptop), secrets.token_bytes take similar time like random.Random.randbytes, and base64.urlsafe_b64encode take more time than random bytes generation.
On Ubuntu 20.04(my cloud server, may lack entropy), secrets.token_bytes take 15x more time than random.Random.randbytes, but take similar time like random.SystemRandom.randbytes
Since secrets.token_bytes use random.SystemRandom.randbytes use os.urandom (thus they are exactly same), you may replace secrets.token_bytes by os.urandom if performance is crucial.
In Python3.9, base64.urlsafe_b64encode is a combination of base64.b64encode and bytes.translate, thus take ~30% more time.
random.Random.randbytes(n) is implemented by random.Random.getrandbits(n * 8).to_bytes(n, 'little'), thus 3x slower. (However, random.SystemRandom.getrandbits is implemented with random.SystemRandom.randbytes)
base64.b32encode is dramatically slower(5x for 6 bytes, 17x for 480 bytes) than base64.b64encode because there are a lots of python code in base64.b32encode, but base64.b64encode just call binascii.b2a_base64 (C implemented).
However, there is a python branch statement if altchars is not None: in base64.b64encode, which will introduce not negligible overhead when process small data, binascii.b2a_base64(data, newline=False) may be better.