0

I put together this code which generates a string of 11 random printable ascii characters:

import random
foo=[]
for n in range(11):
    foo.append(chr(random.randint(32,126)))
print "".join(foo)

It works fine, but I can't help feel that there might be a more efficient way than calling "append" 11 times. Any tips in making it more Pythonic?

David
  • 265
  • 4
  • 8

4 Answers4

6

Use a list comprehension:

foo = [chr(random.randint(32,126)) for _ in xrange(11)]

You can combine that with the str.join():

print ''.join([chr(random.randint(32,126)) for _ in xrange(11)])

I've used xrange() here since you don't need the list produced by range(); only the sequence.

Quick demo:

>>> import random
>>> ''.join([chr(random.randint(32,126)) for _ in xrange(11)])
'D}H]qxfD6&,'
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

You can do it using some functions to make your work more robust.

from random import randint

def random_ascii_string(length=11):
    return ''.join([random_ascii_char() for _ in range(length)])

def random_ascii_char():
    return chr(randint(32,126))

Using it:

>>> random_ascii_string(11)
'.K#d7#q d]%'
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
0

You don't need the intermediate step of putting it into a list:

import random
foo=''
for n in range(11):
    foo += chr(random.randint(32,126))
print foo
Brionius
  • 13,858
  • 3
  • 38
  • 49
  • 1
    It was my understand that concatenating strings like that is less efficient. – David Aug 21 '13 at 14:44
  • I'd be surprised - they have to get concatenated one way or the other. Maybe using `join` is faster? I'll check. – Brionius Aug 21 '13 at 14:45
  • I cProfile'd the OP's method vs my method. For 100,000 runs, the OP's `join` method took 4.2s, the string addition method here took 3.6s. – Brionius Aug 21 '13 at 14:49
  • @Brionius: if you do it all at once with a `join` it can use one pass to figure out how long the resulting string is going to be and allocate the right amount of space from the start. Otherwise you'll have to do unnecessary copies and resizes. Compare `''.join(['a']*10000)` with the loop equiv. (For small sizes you're just measuring the details of interpreter implementation which are hard to distinguish from noise.) – DSM Aug 21 '13 at 14:51
  • Yeah, that sounds reasonable. – Brionius Aug 21 '13 at 14:52
  • The performance difference between `''.join()` and `s += "foo"` depends on the version of Python. Historically, `+=` performed significantly worse than `''.join`, and great effort was spent optimizing concatenation because it was a common source of complaint. Many developers from that era still reach for `join()` first out of habit and folklore. – bgporter Aug 21 '13 at 14:54
  • @Brionius: `str.join()` builds **one** new string object, and copies over the bytes from the concated values into that new object. Your version creates 11 new string objects, one for each concatenation. Creating new objects is costly. – Martijn Pieters Aug 21 '13 at 14:58
0

The following will print the same thing as your method.

print ''.join(chr(random.randint(32,126)) for n in range(11))
pradyunsg
  • 18,287
  • 11
  • 43
  • 96