19

In Python, how to generate a 12-digit random number? Is there any function where we can specify a range like random.range(12)?

import random
random.randint()

The output should be a string with 12 digits in the range 0-9 (leading zeros allowed).

dda
  • 6,030
  • 2
  • 25
  • 34
Rajeev
  • 44,985
  • 76
  • 186
  • 285

6 Answers6

38

Whats wrong with a straightforward approach?

>>> import random
>>> random.randint(100000000000,999999999999)
544234865004L

And if you want it with leading zeros, you need a string.

>>> "%0.12d" % random.randint(0,999999999999)
'023432326286'

Edit:

My own solution to this problem would be something like this:

import random

def rand_x_digit_num(x, leading_zeroes=True):
    """Return an X digit number, leading_zeroes returns a string, otherwise int"""
    if not leading_zeroes:
        # wrap with str() for uniform results
        return random.randint(10**(x-1), 10**x-1)  
    else:
        if x > 6000:
            return ''.join([str(random.randint(0, 9)) for i in xrange(x)])
        else:
            return '{0:0{x}d}'.format(random.randint(0, 10**x-1), x=x)

Testing Results:

>>> rand_x_digit_num(5)
'97225'
>>> rand_x_digit_num(5, False)
15470
>>> rand_x_digit_num(10)
'8273890244'
>>> rand_x_digit_num(10)
'0019234207'
>>> rand_x_digit_num(10, False)
9140630927L

Timing methods for speed:

def timer(x):
        s1 = datetime.now()
        a = ''.join([str(random.randint(0, 9)) for i in xrange(x)])
        e1 = datetime.now()
        s2 = datetime.now()
        b = str("%0." + str(x) + "d") % random.randint(0, 10**x-1)
        e2 = datetime.now()
        print "a took %s, b took %s" % (e1-s1, e2-s2)

Speed test results:

>>> timer(1000)
a took 0:00:00.002000, b took 0:00:00
>>> timer(10000)
a took 0:00:00.021000, b took 0:00:00.064000
>>> timer(100000)
a took 0:00:00.409000, b took 0:00:04.643000
>>> timer(6000)
a took 0:00:00.013000, b took 0:00:00.012000
>>> timer(2000)
a took 0:00:00.004000, b took 0:00:00.001000

What it tells us:

For any digit under around 6000 characters in length my method is faster - sometimes MUCH faster, but for larger numbers the method suggested by arshajii looks better.

Community
  • 1
  • 1
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
  • Oh God! Please use `10**11` and `10**12 -1`. Otherwise these numbers become very difficult to debug/maintain – inspectorG4dget Nov 21 '12 at 15:18
  • of course i would never have crazy numbers like that in code, its just for the answer to make it clear what is going on. my solution would not look like that at all. – Inbar Rose Nov 21 '12 at 15:19
  • 1
    Your solution returns an int OR a string - that is not how you intended it to work, right? Good example why, at least sometimes, static typing has its advantages – Argeman Nov 21 '12 at 15:35
  • @Argeman you are correct that it is intended, as you notice there is a parameter in the function i wrote `leading_zeroes=True` by default it returns strings, if you turn it off explicitly then you should know you will be getting int/long – Inbar Rose Nov 21 '12 at 15:41
  • 1
    Oh, okay, than you solution is correct. In my OPINION its very bad design to let a function return different datatypes if there is no VERY good reason. – Argeman Nov 21 '12 at 15:50
  • @Argeman if you prefer the parameter could read "return_int" and be `False` by default, and then just have the if/else reversed. – Inbar Rose Nov 21 '12 at 15:56
  • You don't have to agree with my opinion of course, but it's still no good idea to have different datatypes returning in my opinion. But of course, with a name like "return_int" it is much more clear what will happen if i change the function call... – Argeman Nov 21 '12 at 16:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/19898/discussion-between-argeman-and-inbar-rose) – Argeman Nov 21 '12 at 16:12
  • Very elegant solution! +1 – FearlessFuture May 08 '14 at 14:54
5

Do random.randrange(10**11, 10**12). It works like randint meets range

From the documentation:

randrange(self, start, stop=None, step=1, int=<type 'int'>, default=None, maxwidth=9007199254740992L) method of random.Random instance
    Choose a random item from range(start, stop[, step]).

    This fixes the problem with randint() which includes the
    endpoint; in Python this is usually not what you want.
    Do not supply the 'int', 'default', and 'maxwidth' arguments.

This is effectively like doing random.choice(range(10**11, 10**12)) or random.randint(10**1, 10**12-1). Since it conforms to the same syntax as range(), it's a lot more intuitive and cleaner than these two alternatives

If leading zeros are allowed:

"%012d" %random.randrange(10**12)
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • 2
    Why use `random.randrange(10**11, 10**12)` over `random.randint(10**11, 10**12)`? – cmh Nov 21 '12 at 15:09
  • 3
    @cmh: because `randrange()` does *not* include the endpoint. You'd have to use `random.randint(10**11, 10**12-1)` instead. – Martijn Pieters Nov 21 '12 at 15:10
  • @MartijnPieters ah ok. Then why use `random.randrange(10**11, 10**12)` over `random.randint(10**11, 10**12 - 1)`? – cmh Nov 21 '12 at 15:11
  • `random.randint(a,b)` returns a random `int` from `[a, b]`, i.e. it sometimes returns `b` as well. `random.randrange(a,b)` returns a random `int` from `[a, b)`, and will therefore never return `b`. It's like calling `random.randint(10**1, 10**12-1)` – inspectorG4dget Nov 21 '12 at 15:12
  • 2
    @cmh: the [implementation of `randint(a, b)`](http://hg.python.org/cpython/file/2.7/Lib/random.py#l237) *uses* `randrange(a, b+1)` internally. Using `randrange()` directly means you save a stack push, it'll be a little faster. – Martijn Pieters Nov 21 '12 at 15:12
  • @StevenRumbalski: `randrange()` returns a single number too. The only difference between `randint()` and `randrange()` is that the end value is included in the first, excluded in the second method. – Martijn Pieters Nov 21 '12 at 15:18
4

Since leading zeros are allowed (by your comment), you could also use:

int(''.join(str(random.randint(0,9)) for _ in xrange(12)))

EDIT: Of course, if you want a string, you can just leave out the int part:

''.join(str(random.randint(0,9)) for _ in xrange(12))

This seems like the most straightforward way to do it in my opinion.

arshajii
  • 127,459
  • 24
  • 238
  • 287
2

There are many ways to do that:

import random

rnumber1 = random.randint(10**11, 10**12-1) # randint includes endpoint
rnumber2 = random.randrange(10**11, 10**12) # randrange does not

# useful if you want to generate some random string from your choice of characters
digits = "123456789"
digits_with_zero = digits + "0"

rnumber3 = random.choice(digits) + ''.join(random.choice(digits_with_zero) for _ in range(11))
khachik
  • 28,112
  • 9
  • 59
  • 94
1
from random import randint

def random_with_N_digits(n):
    range_start = 10**(n-1)
    range_end = (10**n)-1
    return randint(range_start, range_end)

print random_with_N_digits(12)
Calvin Cheng
  • 35,640
  • 39
  • 116
  • 167
1

This may not be exactly what you're looking for, but a library like rstr let's you generate random strings. With that all you would need is (leading 0 allowed):

import rstr
foo = rstr.digits(12)
ckb
  • 6,933
  • 3
  • 15
  • 11