谁还没个明天
2010-02-13 12:23
采纳率: 50%
浏览 1.1k

在 Python 中使用大写字母和数字随机生成字符串

I want to generate a string of size N.

It should be made up of numbers and uppercase English letters such as:

  • 6U1S75
  • 4Z4UKK
  • U911K4

How can I achieve this in a pythonic way?

转载于:https://stackoverflow.com/questions/2257441/random-string-generation-with-upper-case-letters-and-digits-in-python

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

25条回答 默认 最新

  • Memor.の 2010-02-13 12:26
    已采纳

    Answer in one line:

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

    or even shorter starting with Python 3.6 using random.choices():

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

    A cryptographically more secure version; see https://stackoverflow.com/a/23728630/2213647:

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

    In details, with a clean function for further reuse:

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

    How does it work ?

    We import string, a module that contains sequences of common ASCII characters, and random, a module that deals with random generation.

    string.ascii_uppercase + string.digits just concatenates the list of characters representing uppercase ASCII chars and digits:

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

    Then we use a list comprehension to create a list of 'n' elements:

    >>> 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']
    

    In the example above, we use [ to create the list, but we don't in the id_generator function so Python doesn't create the list in memory, but generates the elements on the fly, one by one (more about this here).

    Instead of asking to create 'n' times the string elem, we will ask Python to create 'n' times a random character, picked from a sequence of characters:

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

    Therefore random.choice(chars) for _ in range(size) really is creating a sequence of size characters. Characters that are randomly picked from 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']
    

    Then we just join them with an empty string so the sequence becomes a string:

    >>> ''.join(['a', 'b', 'b'])
    'abb'
    >>> [random.choice('abcde') for _ in range(3)]
    ['d', 'c', 'b']
    >>> ''.join(random.choice('abcde') for _ in range(3))
    'dac'
    
    点赞 评论
  • 游.程 2010-02-13 12:35

    Taking the answer from Ignacio, this works with Python 2.6:

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

    Example output:

    JQUBT2

    点赞 评论
  • ?yb? 2010-02-13 12:44

    A simpler, faster but slightly less random way is to use random.sample instead of choosing each letter separately, If n-repetitions are allowed, enlarge your random basis by n times e.g.

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

    Note: random.sample prevents character reuse, multiplying the size of the character set makes multiple repetitions possible, but they are still less likely then they are in a pure random choice. If we go for a string of length 6, and we pick 'X' as the first character, in the choice example, the odds of getting 'X' for the second character are the same as the odds of getting 'X' as the first character. In the random.sample implementation, the odds of getting 'X' as any subsequent character are only 6/7 the chance of getting it as the first character

    点赞 评论
  • 狐狸.fox 2012-02-10 23:27

    I thought no one had answered this yet lol! But hey, here's my own go at it:

    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))], "")
    
    点赞 评论
  • ℙℕℤℝ 2012-09-13 04:32

    If you need a random string rather than a pseudo random one, you should use os.urandom as the source

    from os import urandom
    from itertools import islice, imap, repeat
    import string
    
    def rand_string(length=5):
        chars = set(string.ascii_uppercase + string.digits)
        char_gen = (c for c in imap(urandom, repeat(1)) if c in chars)
        return ''.join(islice(char_gen, None, length))
    
    点赞 评论
  • from.. 2013-01-08 08:51

    This method is slightly faster, and slightly more annoying, than the random.choice() method Ignacio posted.

    It takes advantage of the nature of pseudo-random algorithms, and banks on bitwise and and shift being faster than generating a new random number for each character.

    # must be length 32 -- 5 bits -- the question didn't specify using the full set
    # of uppercase letters ;)
    _ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
    
    def generate_with_randbits(size=32):
        def chop(x):
            while x:
                yield x & 31
                x = x >> 5
        return  ''.join(_ALPHABET[x] for x in chop(random.getrandbits(size * 5))).ljust(size, 'A')
    

    ...create a generator that takes out 5 bit numbers at a time 0..31 until none left

    ...join() the results of the generator on a random number with the right bits

    With Timeit, for 32-character strings, the timing was:

    [('generate_with_random_choice', 28.92901611328125),
     ('generate_with_randbits', 20.0293550491333)]
    

    ...but for 64 character strings, randbits loses out ;)

    I would probably never use this approach in production code unless I really disliked my co-workers.

    edit: updated to suit the question (uppercase and digits only), and use bitwise operators & and >> instead of % and //

    点赞 评论
  • Memor.の 2013-06-26 15:11

    Simply use Python's builtin uuid:

    If UUIDs are okay for your purposes, use the built-in uuid package.

    One Line Solution:

    import uuid; uuid.uuid4().hex.upper()[0:6]

    In Depth Version:

    Example:

    import uuid
    uuid.uuid4() #uuid4 => full random uuid
    # Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')
    

    If you need exactly your format (for example, "6U1S75"), you can do it like this:

    import uuid
    
    def my_random_string(string_length=10):
        """Returns a random string of length string_length."""
        random = str(uuid.uuid4()) # Convert UUID format to a Python string.
        random = random.upper() # Make all characters uppercase.
        random = random.replace("-","") # Remove the UUID '-'.
        return random[0:string_length] # Return the random string.
    
    print(my_random_string(6)) # For example, D9E50C
    
    点赞 评论
  • python小菜 2013-12-19 17:51

    Based on another Stack Overflow answer, Most lightweight way to create a random string and a random hexadecimal number, a better version than the accepted answer would be:

    ('%06x' % random.randrange(16**6)).upper()
    

    much faster.

    点赞 评论
  • 狐狸.fox 2014-01-30 04:13
    >>> import random
    >>> str = []
    >>> chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
    >>> num = int(raw_input('How long do you want the string to be?  '))
    How long do you want the string to be?  10
    >>> for k in range(1, num+1):
    ...    str.append(random.choice(chars))
    ...
    >>> str = "".join(str)
    >>> str
    'tm2JUQ04CK'
    

    The random.choice function picks a random entry in a list. You also create a list so that you can append the character in the for statement. At the end str is ['t', 'm', '2', 'J', 'U', 'Q', '0', '4', 'C', 'K'], but the str = "".join(str) takes care of that, leaving you with 'tm2JUQ04CK'.

    Hope this helps!

    点赞 评论
  • 衫裤跑路 2014-05-19 01:41

    This Stack Overflow quesion is the current top Google result for "random string Python". The current top answer is:

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

    This is an excellent method, but the PRNG in random is not cryptographically secure. I assume many people researching this question will want to generate random strings for encryption or passwords. You can do this securely by making a small change in the above code:

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

    Using random.SystemRandom() instead of just random uses /dev/urandom on *nix machines and CryptGenRandom() in Windows. These are cryptographically secure PRNGs. Using random.choice instead of random.SystemRandom().choice in an application that requires a secure PRNG could be potentially devastating, and given the popularity of this question, I bet that mistake has been made many times already.

    If you're using python3.6 or above, you can use the new secrets module.

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

    The module docs also discuss convenient ways to generate secure tokens and best practices.

    点赞 评论
  • ~Onlooker 2014-08-26 11:47

    A faster, easier and more flexible way to do this is to use the strgen module (pip install StringGenerator).

    Generate a 6-character random string with upper case letters and digits:

    >>> from strgen import StringGenerator as SG
    >>> SG("[\u\d]{6}").render()
    u'YZI2CI'
    

    Get a unique list:

    >>> SG("[\l\d]{10}").render_list(5,unique=True)
    [u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']
    

    Guarantee one "special" character in the string:

    >>> SG("[\l\d]{10}&[\p]").render()
    u'jaYI0bcPG*0'
    

    A random HTML color:

    >>> SG("#[\h]{6}").render()
    u'#CEdFCa'
    

    etc.

    We need to be aware that this:

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

    might not have a digit (or uppercase character) in it.

    strgen is faster in developer-time than any of the above solutions. The solution from Ignacio is the fastest run-time performing and is the right answer using the Python Standard Library. But you will hardly ever use it in that form. You will want to use SystemRandom (or fallback if not available), make sure required character sets are represented, use unicode (or not), make sure successive invocations produce a unique string, use a subset of one of the string module character classes, etc. This all requires lots more code than in the answers provided. The various attempts to generalize a solution all have limitations that strgen solves with greater brevity and expressive power using a simple template language.

    It's on PyPI:

    pip install StringGenerator
    

    Disclosure: I'm the author of the strgen module.

    点赞 评论
  • derek5. 2014-09-27 19:12

    A simple one:

    import string
    import random
    character = string.lowercase + string.uppercase + string.digits + string.punctuation
    char_len = len(character)
    # you can specify your password length here
    pass_len = random.randint(10,20)
    password = ''
    for x in range(pass_len):
        password = password + character[random.randint(0,char_len-1)]
    print password
    
    点赞 评论
  • 旧行李 2015-02-02 18:02

    For those of you who enjoy functional python:

    from itertools import imap, starmap, islice, repeat
    from functools import partial
    from string import letters, digits, join
    from random import choice
    
    join_chars = partial(join, sep='')
    identity = lambda o: o
    
    def irand_seqs(symbols=join_chars((letters, digits)), length=6, join=join_chars, select=choice, breakup=islice):
        """ Generates an indefinite sequence of joined random symbols each of a specific length
        :param symbols: symbols to select,
            [defaults to string.letters + string.digits, digits 0 - 9, lower and upper case English letters.]
        :param length: the length of each sequence,
            [defaults to 6]
        :param join: method used to join selected symbol, 
            [defaults to ''.join generating a string.]
        :param select: method used to select a random element from the giving population. 
            [defaults to random.choice, which selects a single element randomly]
        :return: indefinite iterator generating random sequences of giving [:param length]
        >>> from tools import irand_seqs
        >>> strings = irand_seqs()
        >>> a = next(strings)
        >>> assert isinstance(a, (str, unicode))
        >>> assert len(a) == 6
        >>> assert next(strings) != next(strings)
        """
        return imap(join, starmap(breakup, repeat((imap(select, repeat(symbols)), None, length))))
    

    It generates an indefinite [infinite] iterator, of joined random sequences, by first generating an indefinite sequence of randomly selected symbol from the giving pool, then breaking this sequence into length parts which is then joined, it should work with any sequence that supports getitem, by default it simply generates a random sequence of alpha numeric letters, though you can easily modify to generate other things:

    for example to generate random tuples of digits:

    >>> irand_tuples = irand_seqs(xrange(10), join=tuple)
    >>> next(irand_tuples)
    (0, 5, 5, 7, 2, 8)
    >>> next(irand_tuples)
    (3, 2, 2, 0, 3, 1)
    

    if you don't want to use next for generation you can simply make it callable:

    >>> irand_tuples = irand_seqs(xrange(10), join=tuple)
    >>> make_rand_tuples = partial(next, irand_tuples) 
    >>> make_rand_tuples()
    (1, 6, 2, 8, 1, 9)
    

    if you want to generate the sequence on the fly simply set join to identity.

    >>> irand_tuples = irand_seqs(xrange(10), join=identity)
    >>> selections = next(irand_tuples)
    >>> next(selections)
    8
    >>> list(selections)
    [6, 3, 8, 2, 2]
    

    As others have mentioned if you need more security then set the appropriate select function:

    >>> from random import SystemRandom
    >>> rand_strs = irand_seqs(select=SystemRandom().choice)
    'QsaDxQ'
    

    the default selector is choice which may select the same symbol multiple times for each chunk, if instead you'd want the same member selected at most once for each chunk then, one possible usage:

    >>> from random import sample
    >>> irand_samples = irand_seqs(xrange(10), length=1, join=next, select=lambda pool: sample(pool, 6))
    >>> next(irand_samples)
    [0, 9, 2, 3, 1, 6]
    

    we use sample as our selector, to do the complete selection, so the chunks are actually length 1, and to join we simply call next which fetches the next completely generated chunk, granted this example seems a bit cumbersome and it is ...

    点赞 评论
  • derek5. 2015-05-04 19:19
    >>> import string 
    >>> import random
    

    the following logic still generates 6 character random sample

    >>> print ''.join(random.sample((string.ascii_uppercase+string.digits),6))
    JT7K3Q
    

    No need to multiply by 6

    >>> print ''.join(random.sample((string.ascii_uppercase+string.digits)*6,6))
    
    TK82HK
    
    点赞 评论
  • 乱世@小熊 2015-07-09 00:06

    You can use the code

    var chars = "ABC123";
            var random = new Random();
            var result = new string(
                Enumerable.Repeat(chars, 7) //Change 7 to any number of characters you want in your outcome
                          .Select(s => s[random.Next(s.Length)])
                          .ToArray());
    
            textBox1.Text = result;
    

    This will random spit out a random 7 alphanumeric pattern, simply change the 7 to any number you wish and it will produce that many numbers and/or letters.

    Another way to write this is as follows...

    var chars = "ABC123";
    var stringChars = new char[7]; //Change 7 to any number of characters you want in your outcome
    var random = new Random();
    
    for (int i = 0; i < stringChars.Length; i++)
    {
    
    stringChars[i] = chars[random.Next(chars.Length)];
    
    }
    
    var finalString = new String(stringChars);
    
    textBox1.Text = finalstring;`
    

    I am unsure of how to add restrictions such as making it to where it does not allow certain numbers and/or letters to be next to each other or repeat such as getting "AAA123" if anyone knows how to restrict the outcome to have something like this please comment back

    点赞 评论
  • Didn"t forge 2015-12-01 10:04
    import uuid
    lowercase_str = uuid.uuid4().hex  
    

    lowercase_str is a random value like 'cea8b32e00934aaea8c005a35d85a5c0'

    uppercase_str = lowercase_str.upper()
    

    uppercase_str is 'CEA8B32E00934AAEA8C005A35D85A5C0'

    点赞 评论
  • larry*wei 2016-04-22 03:50

    (1) This will give you all caps and numbers:

    import string, random
    passkey=''
    for x in range(8):
        if random.choice([1,2]) == 1:
            passkey += passkey.join(random.choice(string.ascii_uppercase))
        else:
            passkey += passkey.join(random.choice(string.digits))
    print passkey 
    

    (2) If you later want to include lowercase letters in your key, then this will also work:

    import string, random
    passkey=''
    for x in range(8):
        if random.choice([1,2]) == 1:
            passkey += passkey.join(random.choice(string.ascii_letters))
        else:
            passkey += passkey.join(random.choice(string.digits))
    print passkey  
    
    点赞 评论
  • 斗士狗 2016-05-11 11:22
    import string
    from random import *
    characters = string.ascii_letters + string.punctuation  + string.digits
    password =  "".join(choice(characters) for x in range(randint(8, 16)))
    print password
    
    点赞 评论
  • 谁还没个明天 2016-06-18 01:22

    Use Numpy's random.choice() function

    import numpy as np
    import string        
    
    if __name__ == '__main__':
        length = 16
        a = np.random.choice(list(string.ascii_uppercase + string.digits), length)                
        print(''.join(a))
    

    Documentation is here http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html

    点赞 评论
  • local-host 2017-01-04 13:12

    From Python 3.6 on you should use the secrets module if you need it to be cryptographically secure instead of the random module (otherwise this answer is identical to the one of @Ignacio Vazquez-Abrams):

    from secrets import choice
    import string
    
    ''.join([choice(string.ascii_uppercase + string.digits) for _ in range(N)])
    

    One additional note: a list-comprehension is faster in the case of str.join than using a generator expression!

    点赞 评论
  • MAO-EYE 2017-07-01 04:28

    this is a take on Anurag Uniyal 's response and something that i was working on myself.

    import random
    import string
    
    oneFile = open('‪Numbers.txt', 'w')
    userInput = 0
    key_count = 0
    value_count = 0
    chars = string.ascii_uppercase + string.digits + string.punctuation
    
    for userInput in range(int(input('How many 12 digit keys do you want?'))):
        while key_count <= userInput:
            key_count += 1
            number = random.randint(1, 999)
            key = number
    
            text = str(key) + ": " + str(''.join(random.sample(chars*6, 12)))
            oneFile.write(text + "\n")
    oneFile.close()
    
    点赞 评论
  • 妄徒之命 2017-07-20 23:54

    I found this to be simpler and cleaner.

    str_Key           = ""
    str_FullKey       = "" 
    str_CharacterPool = "01234ABCDEFfghij~>()"
    for int_I in range(64): 
        str_Key = random.choice(str_CharacterPool) 
        str_FullKey = str_FullKey + str_Key 
    

    Just change the 64 to vary the length, vary the CharacterPool to do alpha only alpha numeric or numeric only or strange characters or whatever you want.

    点赞 评论
  • csdnceshi62 2017-10-05 16:58

    I would like to suggest you next option:

    import crypt
    n = 10
    crypt.crypt("any sring").replace('/', '').replace('.', '').upper()[-n:-1]
    

    Paranoic mode:

    import uuid
    import crypt
    n = 10
    crypt.crypt(str(uuid.uuid4())).replace('/', '').replace('.', '').upper()[-n:-1]
    
    点赞 评论
  • MAO-EYE 2018-04-22 07:57

    Two methods :

    import random, math
    
    def randStr_1(chars:str, length:int) -> str:
        chars *= math.ceil(length / len(chars))
        chars = letters[0:length]
        chars = list(chars)
        random.shuffle(characters)
    
        return ''.join(chars)
    
    def randStr_2(chars:str, length:int) -> str:
        return ''.join(random.choice(chars) for i in range(chars))
    


    Benchmark :

    from timeit import timeit
    
    setup = """
    import os, subprocess, time, string, random, math
    
    def randStr_1(letters:str, length:int) -> str:
        letters *= math.ceil(length / len(letters))
        letters = letters[0:length]
        letters = list(letters)
        random.shuffle(letters)
        return ''.join(letters)
    
    def randStr_2(letters:str, length:int) -> str:
        return ''.join(random.choice(letters) for i in range(length))
    """
    
    print('Method 1 vs Method 2', ', run 10 times each.')
    
    for length in [100,1000,10000,50000,100000,500000,1000000]:
        print(length, 'characters:')
    
        eff1 = timeit("randStr_1(string.ascii_letters, {})".format(length), setup=setup, number=10)
        eff2 = timeit("randStr_2(string.ascii_letters, {})".format(length), setup=setup, number=10)
        print('\t{}s : {}s'.format(round(eff1, 6), round(eff2, 6)))
        print('\tratio = {} : {}\n'.format(eff1/eff1, round(eff2/eff1, 2)))
    

    Output :

    Method 1 vs Method 2 , run 10 times each.
    
    100 characters:
        0.001411s : 0.00179s
        ratio = 1.0 : 1.27
    
    1000 characters:
        0.013857s : 0.017603s
        ratio = 1.0 : 1.27
    
    10000 characters:
        0.13426s : 0.151169s
        ratio = 1.0 : 1.13
    
    50000 characters:
        0.709403s : 0.855136s
        ratio = 1.0 : 1.21
    
    100000 characters:
        1.360735s : 1.674584s
        ratio = 1.0 : 1.23
    
    500000 characters:
        6.754923s : 7.160508s
        ratio = 1.0 : 1.06
    
    1000000 characters:
        11.232965s : 14.223914s
        ratio = 1.0 : 1.27
    

    The performance of first method is better.

    点赞 评论
  • 七度&光 2018-05-04 04:37

    for python 3 import string, random

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

    点赞 评论

相关推荐 更多相似问题