Miły. Po prostu wygeneruj losową liczbę o długości 30 cyfr szesnastkowych i wydrukuj ją. Oczywiste, gdy zostało wskazane. Niezłe.
eemz
Co ciekawe, trochę zapomniałem, że Python (i moduł random) obsługuje biginti natywnie.
wump
3
Zobacz odpowiedź yaronf poniżej na temat używania string.hexdigits: stackoverflow.com/a/15462293/311288 " string.hexdigitszwraca 0123456789abcdefABCDEF(zarówno małe, jak i duże litery), [...]. Zamiast tego po prostu użyj random.choice('0123456789abcdef')."
Thomas
3
Użyj getrandbitszamiast, randrangeaby uczynić go jeszcze szybszym.
robinst
@robinst ma dobry punkt widzenia. '%030x' % random.getrandbits(60)jest nawet szybszy niż '%030x' % random.randrange(16**30), prawdopodobnie dlatego, że nie musi wykonywać żadnej konwersji do / z dużych intów
Zaletą jest to, że uzyskuje to losowość bezpośrednio z systemu operacyjnego, który może być bezpieczniejszy i / lub szybszy niż random (), i nie musisz go wysiewać.
to interesujące i prawdopodobnie dobry wybór do wygenerowania 30-cyfrowej liczby szesnastkowej, którą chce. prawdopodobnie przydałby się również operator urandom i slice do wygenerowania łańcucha alfanumerycznego.
eemz
Przyjrzałem się innym funkcjom w binascii, mają one base64 i uuencode, ale nie ma możliwości wygenerowania pierwszego rodzaju ciągów, które chce (base36).
wump
1
Czy jest to na tyle losowe / unikalne, że można je wykorzystać, powiedzmy, w tokenach sesji?
W Py3.6 + inną opcją jest użycie nowego standardowego secretsmodułu:
>>> import secrets
>>> secrets.token_hex(15)
'8d9bad5b43259c6ee27d9aadc7b832'>>> secrets.token_urlsafe(22) # may include '_-' unclear if that is acceptable'teRq7IqhaRU0S3euX1ji9f58WzUkrg'
import string
import random
lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(30)]
str = "".join(lst)
printstr
ocwbKCiuAJLRJgM1bWNV1TPSH0F2Lb
Jeden użytkownik musi wypróbować wszystkie metody na tej samej maszynie, aby uzyskać dokładną podstawę. Specyfikacje sprzętu mogą mieć duże znaczenie. >>>> timeit.timeit ("'% 0x'% getrandbits (30 * 4)", "z losowego importu getrandbits") 0.2471246949999113 </pre>
ptay
Dziękuję, to znacznie szybciej niż inne powyżej. %timeit '%030x' % randrange(16**30)daje 1000000 pętli, najlepsze z 3: 1,61 µs na pętlę, a %timeit '%0x' % getrandbits(30 * 4)daje 1000000 pętli, najlepsze z 3: 396 ns na pętlę
frmdstryr
15
Uwaga: random.choice(string.hexdigits)jest niepoprawne, ponieważ string.hexdigitszwraca 0123456789abcdefABCDEF(zarówno małe, jak i duże litery), więc otrzymasz wynik z tendencją, w którym cyfra szesnastkowa „c” jest dwukrotnie bardziej prawdopodobna niż cyfra „7”. Zamiast tego po prostu użyj random.choice('0123456789abcdef').
Jest szybszy w porównaniu do tego, o czym wspomniał jcdyer. To zajmuje ~ 50% jego najszybszej metody.
from numpy.random.mtrand import RandomState
import binascii
rand = RandomState()
lo = 1000000000000000
hi = 999999999999999999
binascii.b2a_hex(rand.randint(lo, hi, 2).tostring())[:30]
>>> timeit.Timer("binascii.b2a_hex(rand.randint(lo,hi,2).tostring())[:30]", \
... 'from __main__ import lo,hi,rand,binascii').timeit()
1.648831844329834 <-- this is on python 2.6.62.253110885620117 <-- this on python 2.7.5
Możesz zmienić parametr size przekazywany do randint (ostatni argument), aby zmienić długość danych wyjściowych w zależności od wymagań. Tak więc dla 60-znakowego:
Niewielka zmiana: binascii.b2a_hex(np.random.rand(np.ceil(N/16)).view(dtype=int))[:N]gdzie N=30.
dan-man
@ dan-man Dzięki za tę opcjonalną metodę. Jednak uważam, że pochłania to co najmniej 5 razy więcej czasu. Czy też to zauważyłeś?
Ethan
0
dodanie jeszcze jednej odpowiedzi do miksu, który działa szybciej niż rozwiązanie @eemz i jest również w pełni alfanumeryczny. Zauważ, że to nie daje odpowiedzi szesnastkowej.
import random
import string
LETTERS_AND_DIGITS = string.ascii_letters + string.digits
defrandom_choice_algo(width):return''.join(random.choice(LETTERS_AND_DIGITS) for i inrange(width))
defrandom_choices_algo(width):return''.join(random.choices(LETTERS_AND_DIGITS, k=width))
print(generate_random_string(10))
# prints "48uTwINW1D"
To z pewnością nie jest najlżejsza wersja, ale jest losowa i łatwo jest dostosować żądany alfabet / długość:
import random
defgenerate(random_chars=12, alphabet="0123456789abcdef"):
r = random.SystemRandom()
return''.join([r.choice(alphabet) for i inrange(random_chars)])
Odpowiedzi:
Mam szybszy dla wyjścia szesnastkowego. Używając tych samych t1 i t2 jak powyżej:
>>> t1 = timeit.Timer("''.join(random.choice('0123456789abcdef') for n in xrange(30))", "import random") >>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii") >>> t3 = timeit.Timer("'%030x' % random.randrange(16**30)", "import random") >>> for t in t1, t2, t3: ... t.timeit() ... 28.165037870407104 9.0292739868164062 5.2836320400238037
t3
wykonuje tylko jedno wywołanie modułu losowego, nie musi budować ani czytać listy, a resztę wykonuje z formatowaniem ciągów.źródło
string.hexdigits
: stackoverflow.com/a/15462293/311288 "string.hexdigits
zwraca0123456789abcdefABCDEF
(zarówno małe, jak i duże litery), [...]. Zamiast tego po prostu użyjrandom.choice('0123456789abcdef')
."getrandbits
zamiast,randrange
aby uczynić go jeszcze szybszym.'%030x' % random.getrandbits(60)
jest nawet szybszy niż'%030x' % random.randrange(16**30)
, prawdopodobnie dlatego, że nie musi wykonywać żadnej konwersji do / z dużych intów30-cyfrowy ciąg szesnastkowy:
>>> import os,binascii >>> print binascii.b2a_hex(os.urandom(15)) "c84766ca4a3ce52c3602bbf02ad1f7"
Zaletą jest to, że uzyskuje to losowość bezpośrednio z systemu operacyjnego, który może być bezpieczniejszy i / lub szybszy niż random (), i nie musisz go wysiewać.
źródło
W Py3.6 + inną opcją jest użycie nowego standardowego
secrets
modułu:>>> import secrets >>> secrets.token_hex(15) '8d9bad5b43259c6ee27d9aadc7b832' >>> secrets.token_urlsafe(22) # may include '_-' unclear if that is acceptable 'teRq7IqhaRU0S3euX1ji9f58WzUkrg'
źródło
import string import random lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(30)] str = "".join(lst) print str ocwbKCiuAJLRJgM1bWNV1TPSH0F2Lb
źródło
random.SystemRandom().choice
Znacznie szybsze rozwiązanie niż te tutaj:
timeit("'%0x' % getrandbits(30 * 4)", "from random import getrandbits") 0.8056681156158447
źródło
%timeit '%030x' % randrange(16**30)
daje 1000000 pętli, najlepsze z 3: 1,61 µs na pętlę, a%timeit '%0x' % getrandbits(30 * 4)
daje 1000000 pętli, najlepsze z 3: 396 ns na pętlęUwaga:
random.choice(string.hexdigits)
jest niepoprawne, ponieważstring.hexdigits
zwraca0123456789abcdefABCDEF
(zarówno małe, jak i duże litery), więc otrzymasz wynik z tendencją, w którym cyfra szesnastkowa „c” jest dwukrotnie bardziej prawdopodobna niż cyfra „7”. Zamiast tego po prostu użyjrandom.choice('0123456789abcdef')
.źródło
Inna metoda:
from Crypto import Random import binascii my_hex_value = binascii.hexlify(Random.get_random_bytes(30))
Chodzi o to, że wartość bajtu jest zawsze równa wartości szesnastkowej .
źródło
funkcja jednowierszowa:
import random import string def generate_random_key(length): return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length)) print generate_random_key(30)
źródło
In [1]: import random In [2]: hex(random.getrandbits(16)) Out[2]: '0x3b19'
źródło
Nawiasem mówiąc, jest to wynik zastosowania
timeit
dwóch sugerowanych podejść:Używając
random.choice()
:>>> t1 = timeit.Timer("''.join(random.choice(string.hexdigits) for n in xrange(30))", "import random, string") >>> t1.timeit() 69.558588027954102
Używając
binascii.b2a_hex()
:>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii") >>> t2.timeit() 16.288421154022217
źródło
Jest szybszy w porównaniu do tego, o czym wspomniał jcdyer. To zajmuje ~ 50% jego najszybszej metody.
from numpy.random.mtrand import RandomState import binascii rand = RandomState() lo = 1000000000000000 hi = 999999999999999999 binascii.b2a_hex(rand.randint(lo, hi, 2).tostring())[:30] >>> timeit.Timer("binascii.b2a_hex(rand.randint(lo,hi,2).tostring())[:30]", \ ... 'from __main__ import lo,hi,rand,binascii').timeit() 1.648831844329834 <-- this is on python 2.6.6 2.253110885620117 <-- this on python 2.7.5
Jeśli chcesz w base64:
binascii.b2a_base64(rand.randint(lo, hi, 3).tostring())[:30]
Możesz zmienić parametr size przekazywany do randint (ostatni argument), aby zmienić długość danych wyjściowych w zależności od wymagań. Tak więc dla 60-znakowego:
binascii.b2a_hex(rand.randint(lo, hi, 4).tostring())[:60]
źródło
binascii.b2a_hex(np.random.rand(np.ceil(N/16)).view(dtype=int))[:N]
gdzieN=30
.dodanie jeszcze jednej odpowiedzi do miksu, który działa szybciej niż rozwiązanie @eemz i jest również w pełni alfanumeryczny. Zauważ, że to nie daje odpowiedzi szesnastkowej.
import random import string LETTERS_AND_DIGITS = string.ascii_letters + string.digits def random_choice_algo(width): return ''.join(random.choice(LETTERS_AND_DIGITS) for i in range(width)) def random_choices_algo(width): return ''.join(random.choices(LETTERS_AND_DIGITS, k=width)) print(generate_random_string(10)) # prints "48uTwINW1D"
szybki benchmark daje
from timeit import timeit from functools import partial arg_width = 10 print("random_choice_algo", timeit(partial(random_choice_algo, arg_width))) # random_choice_algo 8.180561417000717 print("random_choices_algo", timeit(partial(random_choices_algo, arg_width))) # random_choices_algo 3.172438014007639
źródło
To z pewnością nie jest najlżejsza wersja, ale jest losowa i łatwo jest dostosować żądany alfabet / długość:
import random def generate(random_chars=12, alphabet="0123456789abcdef"): r = random.SystemRandom() return ''.join([r.choice(alphabet) for i in range(random_chars)])
źródło