2009-07-31 1 views
97

Мне нужно создать уникальный идентификатор, основанный на случайном значении.Как я могу создать уникальный идентификатор в Python?

+3

Можете ли вы уточнить, какой уникальный идентификатор. Нужно ли быть числом? или может содержать буквы? Приведите несколько примеров типа id. – MitMaro

+0

Возможно, что у всех объектов есть уникальный id 'id (my_object)' или 'id (self)'.Этого было достаточно для того, чтобы я рассматривал все, что находится в python, является объектом и имеет числовой идентификатор; string: 'id ('Hello World')' classes: 'id ('Hello World')', все имеет идентификатор. – ThorSummoner

+1

На самом деле у меня были проблемы с использованием id, он, похоже, имел некоторое отношение к имени переменной, где переменные с тем же именем получали идентификаторы одинаковой переменной только что замененной. Вероятно, избегайте использования идентификатора, если у вас нет хорошего модульного тестирования, и убедитесь, что он ведет себя так, как вы этого хотите. – ThorSummoner

ответ

114

Возможно, uuid.uuid4() может выполнить эту работу. См. uuid для получения дополнительной информации.

+18

Остерегайтесь, библиотека, лежащая в основе этого модуля, является ошибкой и имеет тенденцию разворачивать процесс, который открывает FD. Это исправлено в более новых версиях, но большинство людей, вероятно, пока этого не делают, поэтому я вообще избегаю этого модуля. Вызвал мне основные головные боли при прослушивании гнезд ... –

+2

@Glenn: Любые подробности о том, какая версия багги? Я использую это в производственном коде (и собираюсь использовать его больше в более новой версии). Теперь я боюсь! –

+1

@Matthew: Я не знаю, исправлено ли это с момента исправления, но uuid-бэкэнд, который использует uuidlib forked без закрытия FD, поэтому сокеты TCP, которые у меня были открыты в то время, никогда не будут закрыты, и я не смог бы снова открыть порт позже , Мне пришлось бы вручную убить 'uuidd' как root. Я работал над этим, установив 'uuid._uuid_generate_time' и' uuid._uuid_generate_random' значение None, поэтому модуль 'uuid' никогда не использовал собственную реализацию. (Это действительно должно быть вариантом, так как генерация V4 случайных UUID, вызывающих запуск демона, совершенно ненужна.) –

-7
import time 
def new_id(): 
    time.sleep(0.000001) 
    return time.time() 

В моей системе время.time(), кажется, предлагает 6 значащих цифр после десятичной точки. С небольшим сном он должен быть гарантирован уникальным, по крайней мере, с умеренным количеством случайности в последних двух или трех цифрах.

Вы также можете использовать его, если вы беспокоитесь.

+4

Хеширование это не сделает его более уникальным, и есть сильная вероятность столкновения в конце концов, если более чем один процесс делает это - везде, даже не на одной машине. Это не способ генерировать идентификаторы unque. –

+3

Хеширование остановит людей, угадывая, увеличивая. Я думаю, это будет уникально, если есть только один поток, выдающий идентификаторы. Многое зависит от того, что идентификаторы _for_. (и почему они должны быть как уникальными, так и случайными) –

15

уникальные и случайные взаимоисключающие. возможно, вы этого хотите?

import random 
def uniqueid(): 
    seed = random.getrandbits(32) 
    while True: 
     yield seed 
     seed += 1 

Использование:

unique_sequence = uniqueid() 
id1 = next(unique_sequence) 
id2 = next(unique_sequence) 
id3 = next(unique_sequence) 
ids = list(itertools.islice(unique_sequence, 1000)) 

нет двух возвращается идентификатор же (Unique), и это основано на рандомизированном начального значения

+1

Это не уникально. Если я запускаю его дважды и каждый раз генерирую миллион значений, вероятность столкновения между двумя прогонами значительна. Я должен был бы хранить последнее «семя» каждый раз, чтобы этого избежать, - и тогда нет смысла иметь семя; это просто генератор последовательности. * Статистически * уникальные идентификаторы обычно генерируются из случайных данных; по крайней мере один класс UUID работает таким образом. –

+1

Он уникален, пока каждая уникальная последовательность исходит только из одного вызова uniqueid. нет никакой гарантии уникальности между генераторами. – SingleNegationElimination

+1

При таком условии даже счетчик уникален. –

5
import time 
import random 
import socket 
import hashlib 

def guid(*args): 
    """ 
    Generates a universally unique ID. 
    Any arguments only create more randomness. 
    """ 
    t = long(time.time() * 1000) 
    r = long(random.random()*100000000000000000L) 
    try: 
     a = socket.gethostbyname(socket.gethostname()) 
    except: 
     # if we can't get a network address, just imagine one 
     a = random.random()*100000000000000000L 
    data = str(t)+' '+str(r)+' '+str(a)+' '+str(args) 
    data = hashlib.md5(data).hexdigest() 

    return data 
4

здесь вы можете найти реализацию:

def __uniqueid__(): 
    """ 
     generate unique id with length 17 to 21. 
     ensure uniqueness even with daylight savings events (clocks adjusted one-hour backward). 

     if you generate 1 million ids per second during 100 years, you will generate 
     2*25 (approx sec per year) * 10**6 (1 million id per sec) * 100 (years) = 5 * 10**9 unique ids. 

     with 17 digits (radix 16) id, you can represent 16**17 = 295147905179352825856 ids (around 2.9 * 10**20). 
     In fact, as we need far less than that, we agree that the format used to represent id (seed + timestamp reversed) 
     do not cover all numbers that could be represented with 35 digits (radix 16). 

     if you generate 1 million id per second with this algorithm, it will increase the seed by less than 2**12 per hour 
     so if a DST occurs and backward one hour, we need to ensure to generate unique id for twice times for the same period. 
     the seed must be at least 1 to 2**13 range. if we want to ensure uniqueness for two hours (100% contingency), we need 
     a seed for 1 to 2**14 range. that's what we have with this algorithm. You have to increment seed_range_bits if you 
     move your machine by airplane to another time zone or if you have a glucky wallet and use a computer that can generate 
     more than 1 million ids per second. 

     one word about predictability : This algorithm is absolutely NOT designed to generate unpredictable unique id. 
     you can add a sha-1 or sha-256 digest step at the end of this algorithm but you will loose uniqueness and enter to collision probability world. 
     hash algorithms ensure that for same id generated here, you will have the same hash but for two differents id (a pair of ids), it is 
     possible to have the same hash with a very little probability. You would certainly take an option on a bijective function that maps 
     35 digits (or more) number to 35 digits (or more) number based on cipher block and secret key. read paper on breaking PRNG algorithms 
     in order to be convinced that problems could occur as soon as you use random library :) 

     1 million id per second ?... on a Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz, you get : 

     >>> timeit.timeit(uniqueid,number=40000) 
     1.0114529132843018 

     an average of 40000 id/second 
    """ 
    mynow=datetime.now 
    sft=datetime.strftime 
    # store old datetime each time in order to check if we generate during same microsecond (glucky wallet !) 
    # or if daylight savings event occurs (when clocks are adjusted backward) [rarely detected at this level] 
    old_time=mynow() # fake init - on very speed machine it could increase your seed to seed + 1... but we have our contingency :) 
    # manage seed 
    seed_range_bits=14 # max range for seed 
    seed_max_value=2**seed_range_bits - 1 # seed could not exceed 2**nbbits - 1 
    # get random seed 
    seed=random.getrandbits(seed_range_bits) 
    current_seed=str(seed) 
    # producing new ids 
    while True: 
     # get current time 
     current_time=mynow() 
     if current_time <= old_time: 
      # previous id generated in the same microsecond or Daylight saving time event occurs (when clocks are adjusted backward) 
      seed = max(1,(seed + 1) % seed_max_value) 
      current_seed=str(seed) 
     # generate new id (concatenate seed and timestamp as numbers) 
     #newid=hex(int(''.join([sft(current_time,'%f%S%M%H%d%m%Y'),current_seed])))[2:-1] 
     newid=int(''.join([sft(current_time,'%f%S%M%H%d%m%Y'),current_seed])) 
     # save current time 
     old_time=current_time 
     # return a new id 
     yield newid 

""" you get a new id for each call of uniqueid() """ 
uniqueid=__uniqueid__().next 

import unittest 
class UniqueIdTest(unittest.TestCase): 
    def testGen(self): 
     for _ in range(3): 
      m=[uniqueid() for _ in range(10)] 
      self.assertEqual(len(m),len(set(m)),"duplicates found !") 

надеюсь, что это поможет !

+0

его действительно полезно для меня спасибо – Virbhadrasinh

2

Может быть, эта работа для и

str(uuid.uuid4().fields[-1])[:5] 
+0

не могли бы вы подробно рассказать о своей результирующей странице – serup

+1

Да, понимание трансформации и будет ли оно уникальным, было бы хорошо – alisa

+0

Как это обеспечить уникальность? –

2

Это будет работать очень быстро, но не будет генерировать случайные значения, но однообразно увеличивающиеся из них (для данного потока).

import threading 

_uid = threading.local() 
def genuid(): 
    if getattr(_uid, "uid", None) is None: 
     _uid.tid = threading.current_thread().ident 
     _uid.uid = 0 
    _uid.uid += 1 
    return (_uid.tid, _uid.uid) 

Это безопасно и работает с кортежами может иметь преимущество в отличие от строк нити (короче, если что-нибудь). Если вам не нужна безопасность резьбы, не снимайте резьбовые биты (вместо threading.local, используйте объект() и удалите tid в целом).

Надеюсь, что это поможет.

 Смежные вопросы

  • Нет связанных вопросов^_^