Cách đơn giản nhất để tạo một chuỗi ngẫu nhiên và một số thập lục phân ngẫu nhiên


94

Cách nhẹ nhất để tạo một chuỗi ngẫu nhiên gồm 30 ký tự như sau là gì?

ufhy3skj5nca0d2dfh9hwd2tbk9sw1

Và một số thập lục phân gồm 30 chữ số như sau?

8c6f78ac23b4a7b8c0182d7a89e9b1


3
Làm thế nào (tại sao?) Không có câu trả lời nào (được làm kỹ lưỡng) được chấp nhận?
r2evans

Câu trả lời:


125

Tôi có một cái nhanh hơn cho đầu ra hex. Sử dụng t1 và t2 tương tự như trên:

>>> 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 chỉ thực hiện một lệnh gọi đến mô-đun ngẫu nhiên, không phải tạo hoặc đọc danh sách, sau đó thực hiện phần còn lại với định dạng chuỗi.


5
Đẹp. Chỉ cần tạo một số ngẫu nhiên dài 30 chữ số hex và in nó ra. Rõ ràng khi chỉ ra. Tốt lắm.
eemz

Thật thú vị, tôi đã quên rằng Python (và mô-đun ngẫu nhiên) xử lý bigints nguyên bản.
wump

3
Xem câu trả lời của yaronf bên dưới về cách sử dụng string.hexdigits: stackoverflow.com/a/15462293/311288 " string.hexdigitstrả về 0123456789abcdefABCDEF(cả chữ thường và chữ hoa), [...]. Thay vào đó, chỉ cần sử dụng random.choice('0123456789abcdef')."
Thomas

3
Sử dụng getrandbitsthay vì randrangeđể làm cho nó nhanh hơn.
robinst

@robinst có một điểm tốt. '%030x' % random.getrandbits(60)thậm chí còn nhanh hơn so với '%030x' % random.randrange(16**30), có thể bởi vì nó không có không cần phải làm bất kỳ chuyển đổi sang / từ lớn ints
Dan Lenski

79

Chuỗi hex 30 chữ số:

>>> import os,binascii
>>> print binascii.b2a_hex(os.urandom(15))
"c84766ca4a3ce52c3602bbf02ad1f7"

Ưu điểm là điều này nhận được ngẫu nhiên trực tiếp từ Hệ điều hành, có thể an toàn hơn và / hoặc nhanh hơn ngẫu nhiên () và bạn không phải gieo nó.


điều đó thật thú vị và có lẽ là một lựa chọn tốt để tạo ra số hex gồm 30 chữ số mà anh ấy muốn. có thể có thể sử dụng urandom và một toán tử lát cắt để tạo chuỗi chữ và số.
eemz

Tôi đã xem qua các hàm khác trong binascii, chúng có base64 và uuencode, nhưng không có cách nào để tạo loại chuỗi đầu tiên mà anh ấy muốn (base36).
wump

1
Điều này có đủ ngẫu nhiên / duy nhất để được sử dụng trong mã thông báo phiên không?
moraes

1
A: Không. Đã tìm thấy câu trả lời: stackoverflow.com/questions/817882/unique-session-id-in-python/…
moraes

Làm thế nào để xác định độ dài?
3kstc

53

Trong Py3.6 +, một tùy chọn khác là sử dụng secretsmô-đun tiêu chuẩn mới :

>>> import secrets
>>> secrets.token_hex(15)
'8d9bad5b43259c6ee27d9aadc7b832'
>>> secrets.token_urlsafe(22)   # may include '_-' unclear if that is acceptable
'teRq7IqhaRU0S3euX1ji9f58WzUkrg'

28
import string
import random
lst = [random.choice(string.ascii_letters + string.digits) for n in xrange(30)]
str = "".join(lst)
print str
ocwbKCiuAJLRJgM1bWNV1TPSH0F2Lb

6
và random.choice (string.hexdigits)
eemz

1
Người ta có thể thích mật mã an toàn hơnrandom.SystemRandom().choice
Brian M. Hunt

1
xrange () phải là range () - NameError: name 'xrange' không được xác định
Caleb Bramwell

xrange là chính xác (và thường tốt hơn) trong python 2.x
jcdyer

25

Giải pháp nhanh hơn đáng kể so với những giải pháp ở đây:

timeit("'%0x' % getrandbits(30 * 4)", "from random import getrandbits")
0.8056681156158447

Một người dùng phải thử tất cả các phương pháp trên cùng một máy để có được đường cơ sở chính xác. Thông số kỹ thuật phần cứng có thể tạo ra sự khác biệt lớn. >>>> timeit.timeit ("'% 0x'% getrandbits (30 * 4)", "từ getrandbits nhập ngẫu nhiên") 0,2471246949999113 </pre>
ptay

Cảm ơn bạn, điều này nhanh hơn nhiều so với những người khác ở trên. %timeit '%030x' % randrange(16**30)cho 1000000 vòng, tốt nhất là 3: 1,61 ms mỗi vòng lặp while %timeit '%0x' % getrandbits(30 * 4)cho 1000000 vòng, tốt nhất là 3: 396 ns mỗi vòng lặp
frmdstryr

15

Lưu ý: random.choice(string.hexdigits)không chính xác, vì string.hexdigitstrả về 0123456789abcdefABCDEF(cả chữ thường và chữ hoa), vì vậy bạn sẽ nhận được kết quả thiên vị, với chữ số thập lục phân 'c' có khả năng xuất hiện gấp đôi chữ số '7'. Thay vào đó, chỉ cần sử dụng random.choice('0123456789abcdef').


6

Một phương pháp khác :

from Crypto import Random
import binascii

my_hex_value = binascii.hexlify(Random.get_random_bytes(30))

Vấn đề là: giá trị byte luôn bằng giá trị trong hệ lục phân .


5

hàm một dòng:

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)

3
In [1]: import random                                    

In [2]: hex(random.getrandbits(16))                      
Out[2]: '0x3b19'

FYI: Câu trả lời này đã bị gắn cờ là chất lượng thấp, bạn có thể muốn cải thiện nó.
oguz ismail

Bất kỳ đề xuất để cải thiện?
Bob

Không ý kiến. Tôi chỉ nghĩ rằng bạn nên biết rằng
OGUZ ismail

2

Ngẫu nhiên, đây là kết quả của việc sử dụng timeithai cách tiếp cận đã được đề xuất:

Sử dụng random.choice():

>>> t1 = timeit.Timer("''.join(random.choice(string.hexdigits) for n in xrange(30))", "import random, string")
>>> t1.timeit()
69.558588027954102

Sử dụng binascii.b2a_hex():

>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t2.timeit()
16.288421154022217

2

Có một cái nhanh hơn so với những gì jcdyer đã đề cập. Điều này chiếm ~ 50% phương pháp nhanh nhất của anh ấy.

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

Nếu bạn muốn trong base64:

binascii.b2a_base64(rand.randint(lo, hi, 3).tostring())[:30]

Bạn có thể thay đổi tham số kích thước được truyền vào randint (last arg) để thay đổi độ dài đầu ra dựa trên yêu cầu của bạn. Vì vậy, đối với một ký tự 60:

binascii.b2a_hex(rand.randint(lo, hi, 4).tostring())[:60]

Một biến thể nhỏ: binascii.b2a_hex(np.random.rand(np.ceil(N/16)).view(dtype=int))[:N]ở đâu N=30.
dan-man

@ dan-man Cảm ơn vì phương pháp tùy chọn này. Tuy nhiên, tôi thấy rằng nó tiêu tốn ít nhất gấp 5 lần thời gian. Bạn có nhận thấy điều đó không?
Ethan

0

thêm một câu trả lời nữa vào hỗn hợp hoạt động nhanh hơn giải pháp @eemz và cũng có đầy đủ chữ và số. Lưu ý rằng điều này không cung cấp cho bạn câu trả lời theo hệ thập phân.

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"

điểm chuẩn nhanh chóng mang lại

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

0

Đây chắc chắn không phải là phiên bản nhẹ nhất, nhưng nó là ngẫu nhiên và rất dễ dàng để điều chỉnh bảng chữ cái / độ dài bạn muốn:

import random

def generate(random_chars=12, alphabet="0123456789abcdef"):
    r = random.SystemRandom()
    return ''.join([r.choice(alphabet) for i in range(random_chars)])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.