# Token generation system in py3.7

I've created a system to generate tokens that could potentially be used in some sort of program:

# _gen.py is simply to generate the tokens, not to check them.

import string, secrets, random

# String is for getting all ascii letters and digits.
# Secrets is for a cryptographically secure function to choose chars.
# Random is providing a random number generator.

# Base functions used to generate a token

def _tknFrag(length: int=32):
"""Generates a tknFrag, or Token Fragment."""
return ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(length))

def _tknFragLen():
"""Returns the tknFrag's tknFragLen, or Token Fragment Length, an int in between 30 and 34"""
return int(random.randint(30, 34))

def _insDot(tknFrag: str):
"""Inserts a dot in the tknFrag at the end"""
tknFrag += "."
return tknFrag

def _insDash(tknFrag: str):
"""Inserts a dash in the tknFrag at the end"""
tknFrag += "-"
return tknFrag

def _ins(tknFrag: str):
"""Inserts a dash or a dot inside of the tknFrag"""
return {
"0" : lambda frag: _insDot(tknFrag=frag),
"1" : lambda frag: _insDash(tknFrag=frag)
}[str(random.randint(0, 1))](tknFrag)

# Now on to actually generating the tokens

# This is one last helper function, completely generating a fragment
def tokenFragment(repetition):
"""Generates a fragment with the random length, and the dot/dash. The repetition is to determine wether or not to actually put the dot/dash at the end of the token."""
return _ins(_tknFrag(length=_tknFragLen())) if repetition != 2 else _tknFrag(length=_tknFragLen())

def token():
"""Generates a three-fragment-long token"""
return "".join([tokenFragment(repetition) for repetition in range(3)])

# Gotta test it somehow

if __name__ == '__main__':
print(token())


Here are five results from running the code:

2dD0ZYjV4AOGMzZ2lIg6wVPzwpB82Z.BsX34AaWpvJ7i6jtWzYI1zNRjz2pI0.GRW9Uhfl9P8Xu7pYzoSYutEwuhqjhQnN


AghhjknBMqgKLpD6rR90iXKj2yuT44B.CAyXZJtAE62L97SZUbadGBmXTTSflC9th.RbuKtUDWxQ9ROgwo2OkKYEozHc1ToRz8Q


5sFE1npNyEA7JCz9hHEJFwmP2aX4CY3p.RMiKkilzUp7kmJCigrB6HfOVPkWmsczJ-4DF3qLuQSgdwmRxiOMBLUw1ZLj1Al7n


6FCXlDGWjAKylt5rZFYxOfLecxyyL4Pj-0MGu0B2knedbR8HnFI16gHChWZ8uldQ.chCVuFycHPJXF2tj9wR3mi4W4yuRp3o


rEAi9Rn1lXNkMett8wHXLF0iJLQHbc6lI.ksViH35sOlIwFfvOjVHlyXfMS0Ye58diZB-jEX93wyHTRznkYUJvbADmOrdZZF2D0R0


Note that the dots and dashes are for looks only and serve no purpose.

Well, in the first place I have a question as to why you would need this specific pattern of tokens; it seems for a very specific use case.

Secondly, you use a pretty consistent naming convention in your code (which is very good), but the shortened names and abbreviations make it difficult for a person to understand your code quickly (in my opinion).

Lastly, if you are looking for less code and more speed with the same functionality, I can propose this:

import random
import secrets
import string

FRAGMENT_ALPHABET = string.ascii_letters + string.digits
FRAGMENT_SEPARATOR_OPTIONS = ('.', '-')
FRAGMENT_MIN_LENGTH = 30
FRAGMENT_MAX_LENGTH = 34

def _generate_fragment(length: int, prepend_separator: bool):
prefix = ''
if prepend_separator:
prefix = secrets.choice(FRAGMENT_SEPARATOR_OPTIONS)

s = ''.join(
secrets.choice(FRAGMENT_ALPHABET)
for _ in range(length))

return prefix + s

def token(num_parts: int = 3):
return ''.join(
_generate_fragment(
length=random.randint(FRAGMENT_MIN_LENGTH, FRAGMENT_MAX_LENGTH),
prepend_separator=i > 0)          # only False for the first fragment
for i in range(num_parts))


In this code:

• In my opinion (opinions can be very subjective) the code is still readable, but has less functions and those have explicit long names, which helps users to understand it faster.
• I also put some general parameters as uppercase module variables at the top of the file; this makes it easier to modify and (in my opinion) also easier to read/understand in the code.
• The execution time is less. Comparing the two versions using timeit like this for both versions (with Ubuntu and Python3.6):

>>> timeit.timeit('token()', 'from __main__ import token', number=10000)


I get these results, showing my version as faster using about 8 % less time:

Version    Time      Time comparisson
yours      2.222258   100.0 %
mine       2.060732    92.7 %

• Thank you! Although, the shortened names were not designed to be used by the user. They were designed to be used by the _ins and token functions. – Shiatryx Jan 12 '19 at 19:51