如何在 Python 中生成唯一 ID? [复制]
Posted
技术标签:
【中文标题】如何在 Python 中生成唯一 ID? [复制]【英文标题】:How can I generate a unique ID in Python? [duplicate] 【发布时间】:2010-11-15 16:15:44 【问题描述】:我需要根据随机值生成一个唯一 ID。
【问题讨论】:
您能否更具体地了解哪种唯一 ID。必须是数字吗?还是可以包含字母?举一些id类型的例子。 可能相关,所有对象都有唯一的 idid(my_object)
或 id(self)
。考虑到 python 中的所有内容都是一个对象并且有一个数字 id,这对我来说已经足够了;字符串:id('Hello World')
类:id('Hello World')
,一切都有一个 id。
实际上我在使用id时遇到了麻烦,它似乎与变量名有某种关系,其中同名的变量得到的id与刚刚替换的变量相同。可能避免使用 id ,除非您进行了良好的单元测试并确定它的行为方式符合您的要求。
如何添加评论作为答案?
【参考方案1】:
也许uuid.uuid4()
可能会完成这项工作。请参阅uuid 了解更多信息。
【讨论】:
当心,该模块底层的库是错误的,并且往往会派生一个保持 FD 打开的进程。这在较新的版本中已修复,但大多数人可能还没有,所以我通常避免使用这个模块。听套接字让我很头疼...... @Glenn:关于哪个版本有问题的更多细节?我在生产代码中使用它(并且即将在新版本中推出更多用途)。现在我很害怕! @Matthew:我不知道它是否已经修复,但是使用 uuidlib 的 uuid 后端在没有关闭 FD 的情况下分叉,所以我当时打开的 TCP 套接字永远不会关闭,我以后无法重新开放端口。我必须以 root 身份手动杀死uuidd
。我通过将 uuid._uuid_generate_time
和 uuid._uuid_generate_random
设置为 None 来解决这个问题,因此 uuid
模块从未使用本机实现。 (无论如何,这应该是一个选项;生成 V4 随机 UUID 导致启动守护程序是完全没有必要的。)
5 年了,还有问题吗?
@GlennMaynard 9 年后仍然想知道【参考方案2】:
您可能需要 Python 的 UUID 函数:
21.15. uuid — UUID objects according to RFC 4122
例如:
import uuid
print uuid.uuid4()
7d529dd4-548b-4258-aa8e-23e34dc8d43d
【讨论】:
这应该是答案。更详细! 如果我们只想要特定的位数怎么办?【参考方案3】:unique 和 random 是互斥的。也许你想要这个?
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))
没有两个返回的 id 相同(唯一),这是基于随机种子值
【讨论】:
这不是唯一的。如果我启动它两次,并且每次生成一百万个值,那么两次运行之间发生冲突的可能性就很大。我每次都必须存储最后一个“种子”以避免这种情况——那么拥有种子就没有意义了;它只是一个序列生成器。 统计上唯一的 ID 通常是从随机数据中生成的;至少有一类 UUID 以这种方式工作。 它是唯一的,只要每个唯一序列都来自唯一一次调用 uniqueid。无法保证生成器之间的唯一性。 在这种情况下,即使是计数器也是唯一的。 通过计数器生成唯一 ID 有什么问题吗?这是数据库设计中的常见做法。 您的用法不会那样工作(至少在 2.7 中不会):您需要调用 unique_sequence.next()。【参考方案4】:也许这对你有用
str(uuid.uuid4().fields[-1])[:5]
【讨论】:
你能详细说明你得到的str 是的,了解转换以及它是否仍然是独一无二的会很好 这如何确保唯一性? @Pjl 非常感谢!这是获取唯一 ID 的好方法。 这不是一个好的解决方案。见gist.github.com/randlet/65c3812c648517e365f1d774a0122d18【参考方案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
【讨论】:
【参考方案6】:在这里你可以找到一个实现:
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 !")
希望对你有帮助!
【讨论】:
【参考方案7】:这将很快工作,但不会生成随机值,而是单调增加的值(对于给定的线程)。
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,使用 object() 并完全删除 tid )。
希望对您有所帮助。
【讨论】:
【参考方案8】:也许是uuid 模块?
【讨论】:
以上是关于如何在 Python 中生成唯一 ID? [复制]的主要内容,如果未能解决你的问题,请参考以下文章