大文字と数字のランダム文字列生成

サイズNの文字列を生成したい。

以下のような数字と大文字の英字で構成されている必要があります。

  • 6U1S75
  • 4Z4UKK
  • U911K4

これをpythonicな方法で実現するにはどうしたらいいでしょうか?

ソリューション

**1行で答えてください。

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

また、Python 3.6からはrandom.channels()を使ってもっと短くすることもできます。

''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

暗号的に安全なバージョン; https://stackoverflow.com/a/23728630/2213647:を参照してください。

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

詳細は、再利用のためにクリーンな関数を使用しています:

>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
...    return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'

**どのように機能するの?

一般的なASCII文字の配列を含むモジュールであるstringと、ランダム生成を扱うモジュールであるrandomをインポートします。

string.ascii_uppercase + string.digits`は、ASCIIの大文字と数字を表す文字のリストを連結するだけです。

>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

次に、リスト内包を使って、「n」個の要素からなるリストを作成します。

>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']

上の例では、リストを作成するために [ を使用していますが、id_generator 関数では使用していないので、Python はメモリ上でリストを作成するのではなく、その場で要素を 1 つずつ生成しています (これについては こちら)。

文字列 elem を 'n' 回生成するように要求する代わりに、一連の文字から選ばれたランダムな文字を 'n' 回生成するように Python に要求します。

>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'

したがって random.choice(chars) for _ in range(size) は実際には size の文字列を作成していることになります。chars`からランダムに選ばれた文字。

>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']

そして、それらを空の文字列で結合すると、シーケンスは文字列になります。

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
解説 (27)

もっと簡単で速い方法ですが、ランダム性は若干劣ります。各文字を個別に選択する代わりに、random.sampleを使用します。

import random
import string

char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))

注意。 random.sample は文字の再利用を防ぎます。文字セットのサイズを倍にすることで複数回の繰り返しが可能になりますが、純粋なランダム選択の場合に比べて可能性は低くなります。長さ6の文字列で、1文字目に'X'を選んだ場合、選択の例では、2文字目に'X'がくる確率は、1文字目に'X'がくる確率と同じです。random.sampleの実装では、2番目以降の文字として「X」が得られる確率は、1番目の文字として「X」が得られる確率の6/7しかありません。

解説 (10)

まだ誰も答えていないと思っていました(笑)でもまあ、私なりに考えてみました。

import random

def random_alphanumeric(limit):
    #ascii alphabet of all alphanumerals
    r = (range(48, 58) + range(65, 91) + range(97, 123))
    random.shuffle(r)
    return reduce(lambda i, s: i + chr(s), r[:random.randint(0, len(r))], "")
解説 (2)