web-dev-qa-db-fra.com

Comment générer un UUID aléatoire qui est reproductible (avec une graine) dans Python

La fonction id4 () du module Python uuid génère un UUID aléatoire, et semble en générer un différent à chaque fois:

In [1]: import uuid

In [2]: uuid.uuid4()
Out[2]: UUID('f6c9ad6c-eea0-4049-a7c5-56253bc3e9c0')

In [3]: uuid.uuid4()
Out[3]: UUID('2fc1b6f9-9052-4564-9be0-777e790af58f')

Je voudrais pouvoir générer le même UUID aléatoire chaque fois que j'exécute un script - c'est-à-dire que je voudrais semer le générateur aléatoire dans uuid4(). Y a-t-il un moyen de faire cela? (Ou réaliser cela par d'autres moyens)?

Ce que j'ai essayé jusqu'à présent

Je dois générer un UUID en utilisant la méthode uuid.UUID() avec un entier aléatoire de 128 bits (à partir d'une instance prédéfinie de random.Random()) en entrée:

import uuid
import random

rd = random.Random()
rd.seed(0)
uuid.UUID(rd.getrandbits(128))

Cependant, UUID() ne semble pas accepter cela comme entrée:

Traceback (most recent call last):
  File "uuid_gen_seed.py", line 6, in <module>
    uuid.UUID(rd.getrandbits(128))
  File "/usr/lib/python2.7/uuid.py", line 133, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'long' object has no attribute 'replace'

D'autres suggestions?

27
Kurt Peek

Presque là:

uuid.UUID(int=rd.getrandbits(128))

Cela a été déterminé à l'aide de help:

>>> help(uuid.UUID.__init__)
Help on method __init__ in module uuid:

__init__(self, hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None) unbound uuid.UUID method
    Create a UUID from either a string of 32 hexadecimal digits,
    a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
    in little-endian order as the 'bytes_le' argument, a Tuple of six
    integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
    8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
    the 'fields' argument, or a single 128-bit integer as the 'int'
    argument.  When a string of hex digits is given, curly braces,
    hyphens, and a URN prefix are all optional.  For example, these
    expressions all yield the same UUID:

    UUID('{12345678-1234-5678-1234-567812345678}')
    UUID('12345678123456781234567812345678')
    UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
    UUID(bytes='\x12\x34\x56\x78'*4)
    UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
                  '\x12\x34\x56\x78\x12\x34\x56\x78')
    UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
    UUID(int=0x12345678123456781234567812345678)

    Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
    be given.  The 'version' argument is optional; if given, the resulting
    UUID will have its variant and version set according to RFC 4122,
    overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
22
Alex Hall

Faker rend cela facile

>>> from faker import Faker
>>> f1 = Faker()
>>> f1.seed(4321)
>>> print(f1.uuid4())
cc733c92-6853-15f6-0e49-bec741188ebb
>>> print(f1.uuid4())
a41f020c-2d4d-333f-f1d3-979f1043fae0
>>> f1.seed(4321)
>>> print(f1.uuid4())
cc733c92-6853-15f6-0e49-bec741188ebb
10
citynorman

Je vais l'ajouter ici si quelqu'un a besoin d'un patch de singe dans un UUID prédéfini. Mon code utilise uuid.uuid4() mais pour les tests, je voulais des UUID cohérents. Le code suivant est la façon dont je l'ai fait:

import uuid
import random

# -------------------------------------------
# Remove this block to generate different
# UUIDs everytime you run this code.
# This block should be right below the uuid
# import.
rd = random.Random()
rd.seed(0)
uuid.uuid4 = lambda: uuid.UUID(int=rd.getrandbits(128))
# -------------------------------------------

# Then normal code:

print(uuid.uuid4().hex)
print(uuid.uuid4().hex)
print(uuid.uuid4().hex)
print(uuid.uuid4().hex)

Ceci est basé sur une solution utilisée ici :

import hashlib
import uuid

m = hashlib.md5()
m.update(seed.encode('utf-8'))
new_uuid = uuid.UUID(m.hexdigest())
0
user10229295

Basé sur la solution d'Alex, les éléments suivants fourniraient un UUID4 approprié:

random.seed(123210912)
a = "%32x" % random.getrandbits(128)
rd = a[:12] + '4' + a[13:16] + 'a' + a[17:]
uuid4 = uuid.UUID(rd)
0
Perennial