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__':

Here are five results from running the code:






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

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

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

    return prefix + s

def token(num_parts: int = 3):
    return ''.join(
            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 %
  • \$\begingroup\$ 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. \$\endgroup\$ – Shiatryx Jan 12 '19 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.