Ich möchte eine Zeichenfolge der Größe N generieren.
Es sollte aus Zahlen und englischen Großbuchstaben bestehen, wie zum Beispiel:
Wie kann ich das auf Pythonic Weise erreichen?
Antwort in einer Zeile:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
oder noch kürzer beginnend mit Python 3.6 mit random.choices()
:
''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
Eine kryptografisch sicherere Version; siehe https://stackoverflow.com/a/23728630/2213647 :
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
Im Detail mit einer sauberen Funktion zur weiteren Wiederverwendung:
>>> 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'
Wie funktioniert es?
Wir importieren string
, ein Modul, das Sequenzen gemeinsamer ASCII Zeichen enthält, und random
, ein Modul, das sich mit der Zufallsgenerierung befasst.
string.ascii_uppercase + string.digits
verkettet nur die Liste der Zeichen, die GroßbuchstabenASCII und Ziffern darstellen:
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
Dann verwenden wir ein Listenverständnis, um eine Liste von 'n' Elementen zu erstellen:
>>> 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']
Im obigen Beispiel verwenden wir [
, um die Liste zu erstellen, aber nicht in der Funktion id_generator
, sodass Python die Liste nicht im Speicher erstellt, sondern die generiert Elemente on the fly, eins nach dem anderen (mehr dazu hier ).
Anstatt 'n' mal die Zeichenfolge elem
zu erstellen, werden wir Python bitten, 'n' mal ein zufälliges Zeichen zu erstellen, das aus einer Folge von Zeichen ausgewählt wird:
>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'
Daher erstellt random.choice(chars) for _ in range(size)
tatsächlich eine Folge von size
Zeichen. Zeichen, die zufällig aus chars
ausgewählt werden:
>>> [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']
Dann verbinden wir sie einfach mit einem leeren String, sodass die Sequenz zu einem String wird:
>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Diese Stapelüberlauf-Frage ist das aktuelle Top-Google-Ergebnis für "zufällige Zeichenfolge Python". Die aktuelle Top-Antwort lautet:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
Dies ist eine ausgezeichnete Methode, aber das PRNG in zufälliger Reihenfolge ist nicht kryptografisch sicher. Ich gehe davon aus, dass viele Leute, die diese Frage untersuchen, zufällige Zeichenfolgen für die Verschlüsselung oder Passwörter generieren möchten. Sie können dies sicher tun, indem Sie den obigen Code geringfügig ändern:
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
Die Verwendung von random.SystemRandom()
anstelle eines zufälligen Befehls verwendet/dev/urandom auf * nix-Computern und CryptGenRandom()
in Windows. Dies sind kryptografisch sichere PRNGs. Die Verwendung von random.choice
anstelle von random.SystemRandom().choice
in einer Anwendung, für die ein sicheres PRNG erforderlich ist, kann möglicherweise verheerende Folgen haben. Angesichts der Beliebtheit dieser Frage wette ich, dass dieser Fehler bereits oft gemacht wurde .
Wenn Sie Python3.6 oder höher verwenden, können Sie das neue Geheimnisse -Modul verwenden, wie in Antwort von MSeifert erwähnt:
''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))
In den Moduldokumenten werden auch praktische Möglichkeiten zum Generieren sicherer Token und Best Practices erläutert.
Wenn UUIDs für Ihre Zwecke in Ordnung sind, verwenden Sie das integrierte id -Paket.
import uuid; uuid.uuid4().hex.upper()[0:6]
Beispiel:
import uuid
uuid.uuid4() #uuid4 => full random uuid
# Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')
Wenn Sie genau Ihr Format benötigen (zum Beispiel "6U1S75"), können Sie dies folgendermaßen tun:
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
Eine einfachere, schnellere, aber etwas weniger zufällige Möglichkeit besteht darin, random.sample
zu verwenden, anstatt jeden Buchstaben einzeln auszuwählen. Wenn n-Wiederholungen zulässig sind, vergrößern Sie Ihre Zufallsbasis um das n-fache, z.
import random
import string
char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))
Hinweis: random.sample verhindert die Wiederverwendung von Zeichen. Das Multiplizieren des Zeichensatzes ermöglicht mehrere Wiederholungen, ist jedoch immer noch unwahrscheinlicher als die reine Zufallsauswahl. Wenn wir uns für eine Zeichenfolge der Länge 6 entscheiden und 'X' als erstes Zeichen auswählen, entspricht die Wahrscheinlichkeit, 'X' für das zweite Zeichen zu erhalten, der Wahrscheinlichkeit, 'X' als erstes Zeichen zu erhalten erstes Zeichen. In der random.sample-Implementierung beträgt die Wahrscheinlichkeit, dass ein nachfolgendes Zeichen 'X' enthält, nur 6/7 der Wahrscheinlichkeit, dass es das erste Zeichen ist
import uuid
lowercase_str = uuid.uuid4().hex
lowercase_str
ist ein zufälliger Wert wie 'cea8b32e00934aaea8c005a35d85a5c0'
uppercase_str = lowercase_str.upper()
uppercase_str
ist 'CEA8B32E00934AAEA8C005A35D85A5C0'
Aus der Antwort von Ignacio geht das mit Python 2.6:
import random
import string
N=6
print ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
Beispielausgabe:
JQUBT2
Eine schnellere, einfachere und flexiblere Möglichkeit ist die Verwendung des Moduls strgen
(pip install StringGenerator
).
Generieren Sie eine 6-stellige Zufallszeichenfolge mit Großbuchstaben und Ziffern:
>>> from strgen import StringGenerator as SG
>>> SG("[\u\d]{6}").render()
u'YZI2CI'
Holen Sie sich eine eindeutige Liste:
>>> SG("[\l\d]{10}").render_list(5,unique=True)
[u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']
Garantie ein "Sonderzeichen" in der Zeichenfolge:
>>> SG("[\l\d]{10}&[\p]").render()
u'jaYI0bcPG*0'
Eine zufällige HTML-Farbe:
>>> SG("#[\h]{6}").render()
u'#CEdFCa'
usw.
Wir müssen uns bewusst sein, dass dies:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
möglicherweise ist keine Ziffer (oder kein Großbuchstabe) enthalten.
strgen
ist in der Entwicklerzeit schneller als jede der oben genannten Lösungen. Die Lösung von Ignacio bietet die schnellste Laufzeitleistung und ist die richtige Antwort mit der Standardbibliothek Python. Aber Sie werden es kaum jemals in dieser Form verwenden. Sie möchten SystemRandom (oder Fallback, falls nicht verfügbar) verwenden, sicherstellen, dass die erforderlichen Zeichensätze dargestellt werden, Unicode verwenden (oder nicht), sicherstellen, dass aufeinanderfolgende Aufrufe eine eindeutige Zeichenfolge erzeugen, eine Teilmenge einer der Zeichenklassen des Zeichenfolgenmoduls verwenden. usw. Dies alles erfordert viel mehr Code als in den Antworten angegeben. Die verschiedenen Versuche, eine Lösung zu verallgemeinern, weisen alle Beschränkungen auf, die strgen mit größerer Kürze und Ausdruckskraft unter Verwendung einer einfachen Vorlagensprache löst.
Es ist auf PyPI:
pip install StringGenerator
Offenlegung: Ich bin der Autor des strgen-Moduls.
Basierend auf einer anderen Stack Overflow-Antwort einfachste Methode zum Erstellen einer zufälligen Zeichenfolge und einer zufälligen hexadezimalen Zahl, eine bessere Version als Die akzeptierte Antwort wäre:
('%06x' % random.randrange(16**6)).upper()
viel schneller.
Ab Python 3.6 sollten Sie das secrets
-Modul falls Sie es für kryptografische Sicherheit benötigen anstelle des random
-Moduls verwenden (ansonsten ist diese Antwort identisch) zu dem von @Ignacio Vazquez-Abrams):
from secrets import choice
import string
''.join([choice(string.ascii_uppercase + string.digits) for _ in range(N)])
Eine zusätzliche Anmerkung: Ein Listenverständnis ist bei str.join
schneller als bei der Verwendung eines Generatorausdrucks!
Ich dachte, niemand hätte darauf geantwortet, lol! Aber hey, hier ist meine eigene Sache:
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))], "")
Wenn Sie eine zufällige Zeichenfolge anstelle einer pseudozufälligen Zeichenfolge benötigen, sollten Sie os.urandom
als Quelle verwenden
_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))
_
Diese Methode ist etwas schneller und etwas nerviger als die Methode random.choice (), die Ignacio gepostet hat.
Es nutzt die Natur von Pseudozufallsalgorithmen und setzt auf bitweise Verschiebung, die schneller ist als das Erzeugen einer neuen Zufallszahl für jedes Zeichen.
# 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')
... einen Generator erstellen, der 5 Bit-Zahlen gleichzeitig 0..31 entnimmt, bis keine mehr übrig sind
... verbinde () die Ergebnisse des Generators auf einer Zufallszahl mit den richtigen Bits
Bei Timeit war das Timing für Zeichenfolgen mit 32 Zeichen wie folgt:
[('generate_with_random_choice', 28.92901611328125),
('generate_with_randbits', 20.0293550491333)]
... aber für 64 Zeichenketten verlieren Randbits;)
Ich würde diesen Ansatz wahrscheinlich nie im Produktionscode verwenden, wenn ich meine Kollegen nicht wirklich mochte.
edit: aktualisiert, um der Frage zu entsprechen (nur Großbuchstaben und Ziffern), und bitweise Operatoren & und >> anstelle von% und // verwenden
Ich würde es so machen:
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
Oder nur:
def Rand_string(length, char_set=legals):
return ''.join( random.choice(char_set) for _ in range(length) )
Verwenden Sie die Funktion random.choice () von Numpy
import numpy as np
import string
if __== '__main__':
length = 16
a = np.random.choice(list(string.ascii_uppercase + string.digits), length)
print(''.join(a))
Die Dokumentation finden Sie hier http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html
>>> import string
>>> import random
die folgende Logik generiert weiterhin eine Zufallsstichprobe mit 6 Zeichen
>>> print ''.join(random.sample((string.ascii_uppercase+string.digits),6))
JT7K3Q
Keine Notwendigkeit, mit 6 zu multiplizieren
>>> print ''.join(random.sample((string.ascii_uppercase+string.digits)*6,6))
TK82HK
(1) Dies gibt Ihnen alle Großbuchstaben und Zahlen:
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) Wenn Sie später Kleinbuchstaben in Ihren Schlüssel aufnehmen möchten, funktioniert dies auch:
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
dies ist eine auffassung der antwort von anurag uniyal und etwas, an dem ich selbst gearbeitet habe.
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()
Für diejenigen unter Ihnen, die Spaß an funktionalem Python haben:
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))))
Es erzeugt einen unbestimmten [unendlichen] Iterator von verbundenen zufälligen Sequenzen, indem zuerst eine unbestimmte Sequenz von zufällig ausgewählten Symbolen aus dem gebenden Pool erzeugt wird, dann diese Sequenz in Längenteile zerlegt wird, die dann verbunden werden. Es sollte mit jeder Sequenz funktionieren, die getitem unterstützt Standardmäßig wird einfach eine zufällige Folge von alphanumerischen Buchstaben generiert, die Sie jedoch leicht ändern können, um andere Dinge zu generieren:
zum Beispiel, um zufällige Tupel von Ziffern zu generieren:
>>> 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)
wenn Sie next nicht für die Generierung verwenden möchten, können Sie es einfach aufrufbar machen:
>>> irand_tuples = irand_seqs(xrange(10), join=Tuple)
>>> make_Rand_tuples = partial(next, irand_tuples)
>>> make_Rand_tuples()
(1, 6, 2, 8, 1, 9)
wenn Sie die Sequenz im laufenden Betrieb generieren möchten, setzen Sie einfach 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]
Wie bereits erwähnt, stellen Sie die entsprechende Auswahlfunktion ein, wenn Sie mehr Sicherheit benötigen:
>>> from random import SystemRandom
>>> Rand_strs = irand_seqs(select=SystemRandom().choice)
'QsaDxQ'
der Standardselektor ist choice
, der möglicherweise dasselbe Symbol mehrmals für jeden Block auswählt. Wenn Sie stattdessen möchten, dass dasselbe Element höchstens einmal für jeden Block ausgewählt wird, ist eine Verwendung möglich:
>>> 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]
wir verwenden sample
als unseren Selektor, um die vollständige Auswahl zu treffen, so dass die Chunks tatsächlich die Länge 1 haben, und um beizutreten, rufen wir einfach next
auf, was den nächsten vollständig generierten Chunk abruft, vorausgesetzt, dieses Beispiel scheint ein bisschen umständlich und es ist ...
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="")
Hier kann die Länge der Zeichenkette für die Schleife geändert werden, d. H. Für i im Bereich (1, Länge). Es ist ein einfacher Algorithmus, der leicht zu verstehen ist. Es verwendet eine Liste, sodass Sie nicht benötigte Zeichen verwerfen können.
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
>>> 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'
Die Funktion random.choice
wählt einen zufälligen Eintrag in einer Liste aus. Sie erstellen auch eine Liste, damit Sie das Zeichen in der Anweisung for
anhängen können. Am Ende steht str ['t', 'm', '2', 'J', 'U', 'Q', '0', '4', 'C', 'K'], aber das str = "".join(str)
kümmert sich darum und lässt Sie mit 'tm2JUQ04CK'
zurück.
Hoffe das hilft!
Manchmal kann 0 (Null) & O (Buchstabe O) verwirrend sein. Also benutze ich
import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')
Ein einfaches:
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
Ich habe fast alle Antworten durchgesehen, aber keine davon sieht einfacher aus. Ich empfehle Ihnen, die passgen - Bibliothek zu verwenden, mit der im Allgemeinen zufällige Passwörter erstellt werden.
Sie können zufällige Zeichenfolgen Ihrer Wahl generieren, die aus Länge, Interpunktion, Ziffern, Buchstaben und Groß-/Kleinschreibung bestehen.
Hier ist der Code für Ihren Fall:
from passgen import passgen
string_length = int(input())
random_string = passgen(length=string_length, punctuation=False, digits=True, letters=True, case='upper')
Zwei Methoden:
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)))
Ausgabe:
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
Die Leistung der ersten Methode ist besser.
Ich möchte Ihnen die nächste Option vorschlagen:
import crypt
n = 10
crypt.crypt("any sring").replace('/', '').replace('.', '').upper()[-n:-1]
Paranoic-Modus:
import uuid
import crypt
n = 10
crypt.crypt(str(uuid.uuid4())).replace('/', '').replace('.', '').upper()[-n:-1]
für python 3 Importzeichenfolge, zufällig
'' .join (random.choice (string.ascii_lowercase + string.ascii_uppercase + string.digits) für _ in range (15))