# Most lightweight way to create a random string and a random hexadecimal number

## Question or problem about Python programming:

What is the most lightweight way to create a random string of 30 characters like the following?

And an hexadecimal number of 30 digits like the followin?

## How to solve the problem:

### Solution 1:

I got a faster one for the hex output. Using the same t1 and t2 as above:

```>>> t1 = timeit.Timer("''.join(random.choice('0123456789abcdef') for n in xrange(30))", "import random")
>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t3 = timeit.Timer("'%030x' % random.randrange(16**30)", "import random")
>>> for t in t1, t2, t3:
...     t.timeit()
...
28.165037870407104
9.0292739868164062
5.2836320400238037
```

`t3` only makes one call to the random module, doesn’t have to build or read a list, and then does the rest with string formatting.

### Solution 2:

30 digit hex string:

```>>> import os,binascii
>>> print binascii.b2a_hex(os.urandom(15))
```

The advantage is that this gets randomness directly from the OS, which might be more secure and/or faster than the random(), and you don’t have to seed it.

### Solution 3:

In Py3.6+, another option is to use the new standard `secrets` module:

```>>> import secrets
>>> secrets.token_hex(15)
>>> secrets.token_urlsafe(22)   # may include '_-' unclear if that is acceptable
'teRq7IqhaRU0S3euX1ji9f58WzUkrg'
```

### Solution 4:

```import string
import random
lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(30)]
str = "".join(lst)
print str
ocwbKCiuAJLRJgM1bWNV1TPSH0F2Lb
```

### Solution 5:

Dramatically faster solution than those here:

```timeit("'%0x' % getrandbits(30 * 4)", "from random import getrandbits")
0.8056681156158447
```

### Solution 6:

Note: `random.choice(string.hexdigits)` is incorrect, because `string.hexdigits` returns `0123456789abcdefABCDEF` (both lowercase and uppercase), so you will get a biased result, with the hex digit ‘c’ twice as likely to appear as the digit ‘7’. Instead, just use `random.choice('0123456789abcdef')`.

### Solution 7:

Another Method :

```from Crypto import Random
import binascii

my_hex_value = binascii.hexlify(Random.get_random_bytes(30))
```

The point is : byte value is always equal to the value in hex.

### Solution 8:

one-line function:

```import random
import string

def generate_random_key(length):
return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length))

print generate_random_key(30)
```

### Solution 9:

```In : import random

In : hex(random.getrandbits(16))
Out: '0x3b19'
```

### Solution 10:

Incidentally, this is the result of using `timeit` on the two approaches that have been suggested:

Using `random.choice()`:

```>>> t1 = timeit.Timer("''.join(random.choice(string.hexdigits) for n in xrange(30))", "import random, string")
>>> t1.timeit()
69.558588027954102
```

Using `binascii.b2a_hex()`:

```>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t2.timeit()
16.288421154022217
```