Losowe generowanie ciągów z dużymi literami i cyframi

1335

Chcę wygenerować ciąg o rozmiarze N.

Powinien składać się z cyfr i wielkich liter angielskich, takich jak:

  • 6U1S75
  • 4Z4UKK
  • U911K4

Jak mogę to osiągnąć w pythonowy sposób?

Hellnar
źródło
11
To bardzo popularne pytanie. Chciałbym, aby ekspert dodał swoje podejście do wyjątkowości tych liczb losowych dla 3 najlepszych odpowiedzi, tj. Prawdopodobieństwo kolizji dla zakresu wielkości łańcucha, powiedzmy od 6 do 16.
użytkownik
8
@ bufor Łatwo obliczyć liczbę możliwych kombinacji. 10 cyfr + 26 liter = 36 możliwych znaków, do potęgi 6 (długość łańcucha) wynosi około dwóch miliardów. Moją ogólną zasadą dla losowych wartości jest „jeśli wygenerowałbym wartości dla każdego człowieka na Ziemi, ile wartości mogliby oni mieć dla siebie?”. W takim przypadku byłoby to mniej niż jedna wartość na osobę, więc jeśli ma to na celu identyfikację użytkowników lub obiektów, to jest za mało znaków. Jedną z możliwości byłoby dodanie małych liter, co daje 62 ^ 6 = prawie 57 miliardów unikalnych wartości.
Blixt
1
I choć myślenie o populacji na świecie może wydawać się głupie, to tylko dlatego, że potrzebujesz ogromnego bufora dla potencjalnych kolizji. Zobacz problem urodzinowy: en.wikipedia.org/wiki/Birthday_problem
Blixt
1
@buffer, Byłbyś wtedy zainteresowany tą odpowiedzią .
Anish Ramaswamy,
Czy nie należy tego zmienić na „Kryptograficznie bezpieczne generowanie ciągów losowych ...” ?
smci

Odpowiedzi:

2540

Odpowiedź w jednym wierszu:

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

lub nawet krócej, zaczynając od Pythona 3.6, używając random.choices():

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

Wersja kryptograficznie bezpieczniejsza; patrz https://stackoverflow.com/a/23728630/2213647 :

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

Szczegółowo, z czystą funkcją do dalszego wykorzystania:

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

Jak to działa ?

Importujemy stringmoduł zawierający sekwencje typowych znaków ASCII oraz randommoduł zajmujący się generowaniem losowym.

string.ascii_uppercase + string.digits po prostu łączy listę znaków reprezentujących wielkie znaki i cyfry ASCII:

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

Następnie używamy rozumienia listy, aby utworzyć listę elementów „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']

W powyższym przykładzie używamy [do tworzenia listy, ale nie mamy id_generatorfunkcji, więc Python nie tworzy listy w pamięci, ale generuje elementy w locie, jeden po drugim (więcej o tym tutaj ).

Zamiast prosić o utworzenie „n” razy ciągu elem, poprosimy Pythona o utworzenie „n” razy losowego znaku, wybranego z sekwencji znaków:

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

Dlatego random.choice(chars) for _ in range(size)naprawdę tworzy sekwencję sizeznaków. Znaki wybierane losowo z 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']

Następnie po prostu łączymy je pustym ciągiem, aby sekwencja stała się ciągiem:

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Ignacio Vazquez-Abrams
źródło
7
@jorelli: To nie jest lista; to wyrażenie generatora.
Ignacio Vazquez-Abrams
2
@joreilli: W odpowiedzi dodałem krótką notatkę i link do bardziej szczegółowej odpowiedzi na temat iteracji, zrozumienia listy, generatorów i ewentualnie słowa kluczowego wydajności.
e-satis,
1
Chciałbym zamienić rangez xrange.
Dr Jan-Philip Gehrcke
1
Bardzo przydatne. Co ciekawe, Django używa tego fragmentu kodu do generowania haseł i tokenów CSRF. Chociaż należy wymienić randomz random.SystemRandom(): github.com/django/django/blob/...
użytkownik
1
@ Chiel92, random.sampletworzy próbki bez zamiany, innymi słowy, bez możliwości powtarzania znaków, co nie jest zgodne z wymaganiami PO. Nie sądzę, że byłoby to pożądane w przypadku większości aplikacji.
ontolog,
557

To pytanie o przepełnienie stosu jest obecnie najwyższym wynikiem Google dla „losowego ciągu Python”. Obecna najwyższa odpowiedź to:

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

Jest to doskonała metoda, ale losowy PRNG nie jest kryptograficznie bezpieczny. Zakładam, że wiele osób badających to pytanie będzie chciało generować losowe ciągi do szyfrowania lub haseł. Możesz to zrobić bezpiecznie, wprowadzając niewielką zmianę w powyższym kodzie:

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

Używanie random.SystemRandom()zamiast przypadkowych zastosowań / dev / urandom na maszynach * nix i CryptGenRandom()Windows. Są to kryptograficznie bezpieczne PRNG. Używanie random.choicezamiast random.SystemRandom().choiceaplikacji wymagającej bezpiecznego PRNG może być potencjalnie niszczycielskie, a biorąc pod uwagę popularność tego pytania, założę się, że błąd popełniono już wiele razy.

Jeśli używasz Python3.6 lub nowszego, możesz użyć nowego modułu sekretów , jak wspomniano w odpowiedzi MSeifert :

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

Dokumenty modułu omawiają również wygodne sposoby generowania bezpiecznych tokenów i najlepszych praktyk .

Randy Marsh
źródło
3
Tak, oficjalna biblioteka standardowa dla randomostrzega: „ Ostrzeżenie : Pseudolosowych generatorów tego modułu nie należy używać do celów bezpieczeństwa. Użyj os.urandom () lub SystemRandom, jeśli potrzebujesz kryptograficznie bezpiecznego generatora liczb pseudolosowych. „ Oto ref: random.SystemRandom i os.urandom
lord63. j
4
Świetna odpowiedź. Mała uwaga: Zmieniłeś to, string.uppercaseco może prowadzić do nieoczekiwanych wyników w zależności od zestawu ustawień regionalnych. Użycie string.ascii_uppercase(lub string.ascii_letters + string.digitsdla base62 zamiast base36) jest bezpieczniejsze w przypadkach, w których występuje kodowanie.
Blixt
mała uwaga - lepiej użyć xrangezamiast tego, rangeże ten drugi generuje listę w pamięci, podczas gdy ten pierwszy tworzy iterator.
guyarad
2
czy losowe żądło będzie zawsze wyjątkowe? chciałem użyć klucza podstawowego.
shakthydoss
3
@shakthydoss: nie. Może zwrócić „AAA000”, który jest ciągiem losowym, a następnie „AAA000”, który jest także ciągiem losowym. Musisz jawnie dodać czek na niepowtarzalność.
usr2564301
189

Wystarczy użyć wbudowanego interfejsu użytkownika Pythona:

Jeżeli UUID są w porządku dla swoich potrzeb, korzystać z wbudowanego w UUID opakowaniu.

Rozwiązanie jednoliniowe:

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

W wersji głębokiej:

Przykład:

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

Jeśli potrzebujesz dokładnie swojego formatu (na przykład „6U1S75”), możesz to zrobić w następujący sposób:

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
Bijan
źródło
14
+1 Za przemyślenie pytania. Być może mógłbyś krótko wyjaśnić różnicę między uuid1 a uuid4.
Thomas Ahle
1
Jeśli zrobię uuid1 trzy razy z rzędu, dostaję: d161fd16-ab0f-11e3-9314-00259073e4a8, d3535b56-ab0f-11e3-9314-00259073e4a8, d413be32-ab0f-11e3-9314-00259073e4a8, co wydaje się podejrzane (podobne) pierwsze 8 znaków różni się, a pozostałe są takie same). Nie jest tak w przypadku uuid4
Chase Roberts
9
uui1: Wygeneruj identyfikator UUID na podstawie identyfikatora hosta, numeru sekwencji i bieżącej godziny. uuid4: Wygeneruj losowy UUID.
Bijan
7
Jeśli chcesz pominąć rzutowanie ciągów i zamianę łączników, możesz po prostu wywołać my_uuid.get_hex () lub uuid.uuid4 (). Get_hex (), a to zwróci ciąg wygenerowany z identyfikatora użytkownika, który nie ma łączników.
dshap
8
Czy to dobry pomysł, aby obciąć UUID? W zależności od tego, jak małe string_lengthjest, prawdopodobieństwo zderzenia może stanowić problem.
użytkownik
44

Prostszym, szybszym, ale nieco mniej losowym sposobem jest użycie random.samplezamiast wybierania każdej litery osobno. Jeśli dozwolonych jest n-powtórzeń, powiększ swoją losowość n razy np.

import random
import string

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

Uwaga: random.sample zapobiega ponownemu użyciu znaków, pomnożenie rozmiaru zestawu znaków umożliwia wielokrotne powtórzenia, ale nadal są one mniej prawdopodobne niż w przypadku losowego wyboru. Jeśli zdecydujemy się na ciąg o długości 6 i wybieramy „X” jako pierwszy znak, w przykładzie wyboru szanse na uzyskanie „X” dla drugiego znaku są takie same, jak szanse na uzyskanie „X” jako pierwsza postać. W implementacji random.sample szanse na uzyskanie „X” jako każdej kolejnej postaci mają tylko 6/7 szansy na uzyskanie jej jako pierwszej postaci

Anurag Uniyal
źródło
8
Ten sposób nie jest zły, ale nie jest tak losowy, jak wybieranie każdej postaci osobno, ponieważ samplenigdy nie zobaczysz tej samej postaci dwa razy na liście. Oczywiście, że zawiedzie na Nwięcej niż 36.
bobince
dla danego przypadku użycia (jeśli żadne powtórzenie nie jest w porządku) powiem, że jest to nadal najlepsze rozwiązanie.
Anurag Uniyal
3
Jeden z przykładów ma powtórzenie, więc wątpię, czy chce zabronić powtórzeń.
Mark Byers
5
Jeśli zapobiega random.sample postaci ponownego wykorzystania, mnożąc rozmiar zestawu znaków sprawia, że wiele powtórzeń to możliwe , ale są jeszcze mniej prawdopodobne, to są one w czystej losowego wyboru. Jeśli zdecydujemy się na ciąg o długości 6 i wybieramy „X” jako pierwszy znak, w przykładzie wyboru szanse na uzyskanie „X” dla drugiego znaku są takie same, jak szanse na uzyskanie „X” jako pierwsza postać. W implementacji random.sample szanse na uzyskanie „X” jako każdej kolejnej postaci mają tylko 5/6 szansy na uzyskanie jej jako pierwszej postaci.
pcurry
1
Szansa na powtórzenie określonej postaci spada wraz z przejściem przez wygenerowany ciąg. Generowanie ciągu 6 znaków z 26 wielkich liter plus 10 cyfr, losowy wybór każdego znaku niezależnie, każdy określony ciąg występuje z częstotliwością 1 / (36 ^ 6). Szansa na wygenerowanie „FU3WYE” i „XXXXXX” jest taka sama. W przykładowej implementacji szansa na wygenerowanie „XXXXXX” wynosi (1 / (36 ^ 6)) * ((6/6) * (5/6) * (4/6) * (3/6) * (2 / 6) * (1/6)) z powodu niewymiennej funkcji random.sample. „XXXXXX” jest 324 razy mniej prawdopodobne w przykładowej implementacji.
pcurry
32
import uuid
lowercase_str = uuid.uuid4().hex  

lowercase_str jest wartością losową jak 'cea8b32e00934aaea8c005a35d85a5c0'

uppercase_str = lowercase_str.upper()

uppercase_str jest 'CEA8B32E00934AAEA8C005A35D85A5C0'

Savad KP
źródło
2
uppercase_str[:N+1]
Yajo,
@ Yajo tak, możemy ograniczyć stosowanie krojenia
Savad KP
2
@Yajo: nie, nie chcesz wycinać wartości szesnastkowej. Usuwasz entropię w porównaniu z pełną sekwencją wielkich liter i cyfr. Być może zamiast tego kodowana jest wartość base32 (nieco zmniejszona entropia, z 36 ** n do 32 ** n, wciąż lepsza niż 16 ** n).
Martijn Pieters
19

Szybszym, łatwiejszym i bardziej elastycznym sposobem na to jest użycie strgenmodułu ( pip install StringGenerator).

Wygeneruj losowy ciąg 6 znaków z dużymi literami i cyframi:

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

Uzyskaj unikalną listę:

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

Gwarancja jednego „specjalnego” znaku w ciągu:

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

Losowy kolor HTML:

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

itp.

Musimy mieć świadomość, że to:

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

może nie zawierać cyfr (lub wielkich liter).

strgenczas programowania jest krótszy niż którekolwiek z powyższych rozwiązań. Rozwiązanie firmy Ignacio zapewnia najszybsze działanie w czasie wykonywania i jest właściwą odpowiedzią przy użyciu biblioteki standardowej Python. Ale prawie nigdy nie użyjesz go w tej formie. Będziesz chciał użyć SystemRandom (lub awaryjne, jeśli nie jest dostępne), upewnij się, że wymagane zestawy znaków są reprezentowane, użyj Unicode (lub nie), upewnij się, że kolejne wywołania generują unikatowy ciąg, użyj podzbioru jednej z klas znaków modułu ciągów, itd. To wszystko wymaga znacznie więcej kodu niż w podanych odpowiedziach. Różne próby uogólnienia rozwiązania mają ograniczenia, które często rozwiązują się z większą zwięzłością i mocą ekspresji przy użyciu prostego języka szablonów.

Jest na PyPI:

pip install StringGenerator

Ujawnienie: Jestem autorem modułu strgen.

Paul Wolf
źródło
12

Począwszy od Pythona 3.6, powinieneś używać secretsmodułu, jeśli chcesz go kryptograficznie zabezpieczyć zamiast randommodułu (w przeciwnym razie odpowiedź jest identyczna z odpowiedzią @Ignacio Vazquez-Abrams):

from secrets import choice
import string

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

Jedna dodatkowa uwaga: zrozumienie listy jest szybsze w przypadku str.joinniż użycia wyrażenia generatora!

MSeifert
źródło
10

Na podstawie innej odpowiedzi przepełnienia stosu, najlżejszy sposób na utworzenie losowego ciągu i losowej liczby szesnastkowej , lepsza wersja niż zaakceptowana odpowiedź to:

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

o wiele szybciej.

Gubbi
źródło
1
Jest to miłe, chociaż będzie używać tylko „AF”, a nie „A-Z”. Ponadto kod staje się trochę mniej przyjemny, gdy parametryczny N.
Thomas Ahle
9

Jeśli potrzebujesz ciągu losowego zamiast pseudolosowego , powinieneś użyć go os.urandomjako źródła

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))
John La Rooy
źródło
3
Jak to os.urandomnie jest pseudolosowe? Być może używa lepszego algorytmu do generowania liczb, które są bardziej losowe, ale nadal jest pseudolosowy.
Tyilo,
@Tyilo, zdaję sobie sprawę z różnicy między /dev/randomi /dev/urandom. Problem polega na tym, że /dev/randomblokuje się, gdy entropia jest niewystarczająca, co ogranicza jej przydatność. Na jeden raz pad /dev/urandom nie jest wystarczająco dobry, ale myślę, że jest lepszy niż pseudolosowy.
John La Rooy,
1
Powiedziałbym, że jedno /dev/randomi drugie /dev/urandomjest pseudolosowe, ale może zależeć od twojej definicji.
Tyilo,
9

Myślałem, że nikt jeszcze nie odpowiedział na to lol! Ale hej, oto moje własne:

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))], "")
nemesisfixx
źródło
4
Nie będę głosować za tym, ale myślę, że jest to zbyt skomplikowane, aby wykonać tak proste zadanie. Zwrotem jest potwór. Prosty jest lepszy niż złożony.
Carl Smith
12
@CarlSmith, prawda, moje rozwiązanie wydaje się nieco przesadne w stosunku do zadania, ale zdawałem sobie sprawę z innych prostszych rozwiązań i po prostu chciałem znaleźć alternatywną drogę do dobrej odpowiedzi. Bez wolności kreatywność jest w niebezpieczeństwie, dlatego napisałem ją.
nemesisfixx
7

Ta metoda jest nieco szybsza i nieco bardziej irytująca niż metoda random.choice (), którą opublikował Ignacio.

Wykorzystuje naturę algorytmów pseudolosowych, a banki bitowe i przesuwne są szybsze niż generowanie nowej liczby losowej dla każdego znaku.

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

... stwórz generator, który pobiera 5 liczb bitowych na raz 0..31, dopóki nie zostanie żaden

... dołącz () wyniki generatora na losowej liczbie z odpowiednimi bitami

W przypadku Timeit dla łańcuchów 32-znakowych czas był następujący:

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

... ale w przypadku ciągów 64 znaków randbits przegrywa;)

Prawdopodobnie nigdy nie zastosowałbym tego podejścia w kodzie produkcyjnym, chyba że naprawdę nie lubiłem moich współpracowników.

edycja: zaktualizowano, aby pasowało do pytania (tylko wielkie litery i cyfry), i używa operatorów bitowych & i >> zamiast% i //

Obrabować
źródło
5

Zrobiłbym to w ten sposób:

import random
from string import digits, ascii_uppercase

legals = digits + ascii_uppercase

def rand_string(length, char_set=legals):

    output = ''
    for _ in range(length): output += random.choice(char_set)
    return output

Lub tylko:

def rand_string(length, char_set=legals):

    return ''.join( random.choice(char_set) for _ in range(length) )
Carl Smith
źródło
5

Użyj funkcji random.choice () Numpy

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

Dokumentacja znajduje się tutaj http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html

Mudit Jain
źródło
1
Dlaczego powinienem używać numpy random zamiast python stdlib random?
Pax0r
Ponieważ pozwala na więcej opcji w argumentach, takich jak długość, zmienne prawdopodobieństwo i wybór z zamianą.
Mudit Jain,
5

Czasami 0 (zero) i O (litera O) może być mylące. Więc używam

import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')
Aseem
źródło
4
>>> import string 
>>> import random

poniższa logika nadal generuje losową próbkę o długości 6 znaków

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

Nie ma potrzeby mnożenia przez 6

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

TK82HK
użytkownik128956
źródło
3
Ale ten wariant zmusi wszystkie postacie do bycia innym. I to nie zadziała, jeśli N jest większy niż len (string.ascii_uppercase + string.digits)
MarSoft
3

Dla tych, którzy lubią funkcjonalny 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))))

Generuje nieokreślony [nieskończony] iterator, połączonych losowych sekwencji, najpierw generując nieokreśloną sekwencję losowo wybranego symbolu z puli, a następnie dzieląc tę ​​sekwencję na części długości, które są następnie łączone, powinien działać z dowolną sekwencją, która obsługuje getitem , domyślnie po prostu generuje losową sekwencję liter alfanumerycznych, chociaż można łatwo modyfikować, aby wygenerować inne rzeczy:

na przykład, aby wygenerować losowe krotki cyfr:

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

jeśli nie chcesz używać następnej generacji, możesz po prostu sprawić, że będzie to możliwe:

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

jeśli chcesz generować sekwencję w locie, po prostu ustaw dołącz do tożsamości.

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

Jak wspomnieli inni, jeśli potrzebujesz większego bezpieczeństwa, ustaw odpowiednią funkcję wyboru:

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

domyślnym selektorem jest to, że choicemoże wybrać ten sam symbol wiele razy dla każdej porcji, jeśli zamiast tego chcesz, aby ten sam element był wybrany najwyżej raz dla każdej porcji, możliwe jest jedno użycie:

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

używamy samplejako naszego selektora, aby dokonać pełnego wyboru, więc fragmenty mają w rzeczywistości długość 1, a aby się połączyć, po prostu wywołujemy, nextktóry pobiera następny całkowicie wygenerowany fragment, pod warunkiem, że ten przykład wydaje się trochę niewygodny i jest ...

Samy Vilar
źródło
3

(1) To da ci wszystkie czapki i liczby:

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) Jeśli później chcesz dołączyć małe litery do klucza, zadziała to również:

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  
Jakub
źródło
3

to jest odpowiedź Anurag Uniyal i coś, nad czym pracowałem nad sobą.

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()
Stopit Donk
źródło
2
>>> 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'

random.choiceFunkcja wybiera losowy wpis w liście. Tworzysz także listę, aby móc dołączyć znak do forinstrukcji. Na końcu jest [„t”, „m”, „2”, „J”, „U”, „Q”, „0”, „4”, „C”, „K”], ale str = "".join(str)ujęcia dbaj o to, zostawiając cię z 'tm2JUQ04CK'.

Mam nadzieję że to pomoże!

AJ Uppal
źródło
Fajnie, ale możesz użyć range(num)zamiast tego, a str może być łańcuchem str += random.choice(chars).
sashk
2
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
Natasza
źródło
2
Chociaż ten kod może odpowiedzieć na pytanie, dostarczenie dodatkowego kontekstu dotyczącego tego, dlaczego i / lub jak odpowiada na pytanie, znacznie poprawiłoby jego długoterminową wartość. Proszę edytować swoje odpowiedzi, aby dodać trochę wyjaśnień.
Toby Speight
2
import random
q=2
o=1
list  =[r'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','s','0','1','2','3','4','5','6','7','8','9','0']
while(q>o):
    print("")

    for i in range(1,128):
        x=random.choice(list)
        print(x,end="")

Tutaj długość łańcucha można zmienić dla pętli, tj. Dla i w zakresie (1, długość) Jest to prosty algorytm, który jest łatwy do zrozumienia. używa listy, więc możesz odrzucić niepotrzebne znaki.

lawlie8
źródło
1

Prosty:

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
Hackaholic
źródło
0

Chciałbym zasugerować następną opcję:

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

Tryb paranoiczny:

import uuid
import crypt
n = 10
crypt.crypt(str(uuid.uuid4())).replace('/', '').replace('.', '').upper()[-n:-1]
mrvol
źródło
0

Dwie metody:

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

Wynik :

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

Wydajność pierwszej metody jest lepsza.

Bi Ao
źródło
0

Przeszedłem przez prawie wszystkie odpowiedzi, ale żadna z nich nie wygląda na łatwiejszą. Sugeruję wypróbowanie biblioteki passgen, która jest zwykle używana do tworzenia losowych haseł.

Możesz generować losowe ciągi znaków o wybranej długości, interpunkcji, cyfrach, literach i wielkości liter .

Oto kod twojej sprawy:

from passgen import passgen
string_length = int(input())
random_string = passgen(length=string_length, punctuation=False, digits=True, letters=True, case='upper')
Jarvis
źródło
0

Generuj losowe 16-bajtowe identyfikatory zawierające litery, cyfry, „_” i „-”

os.urandom(16).translate((f'{string.ascii_letters}{string.digits}-_'*4).encode('ascii'))

para gniazd
źródło
-1
import string, random
lower = string.ascii_lowercase
upper = string.ascii_uppercase
digits = string.digits
special = '!"£$%^&*.,@#/?'

def rand_pass(l=4, u=4, d=4, s=4):
    p = []
    [p.append(random.choice(lower)) for x in range(l)]
    [p.append(random.choice(upper)) for x in range(u)]
    [p.append(random.choice(digits)) for x in range(d)]
    [p.append(random.choice(special)) for x in range(s)]
    random.shuffle(p)
    return "".join(p)

print(rand_pass())
# @5U,@A4yIZvnp%51
CONvid19
źródło
-2

Uznałem, że jest to prostsze i czystsze.

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 

Po prostu zmień 64, aby zmienić długość, zmień CharacterPool, aby zrobić tylko alfabet, cyfrę lub cyfrę albo dziwne znaki lub cokolwiek chcesz.

MT Head
źródło