【问题标题】:Python random character string repeated 7/2000 recordsPython随机字符串重复7/2000条记录
【发布时间】:2016-03-01 22:57:23
【问题描述】:

我正在使用以下内容来生成一组随机的字符和数字:

tag = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(36)])

我认为这是一个不错的方法。 36 个字符长度,每个字符是 36 个唯一选项之一。应该是很大的随机性吧?

然后,我使用我认为是唯一的tag 对实例运行查询。结果发现,有 七 (7) 个 条记录具有相同的“随机”tag。所以,我打开了数据库,并运行了一个查询来查看我的标签的可重复性。

事实证明,我的不仅出现了 7 次,而且还有许多标签反复出现。大约有 2000 行,这显然不应该发生。

两个问题:

(1) 我的方法有什么问题,为什么会如此频繁地重复相同的tag

(2) 为每条记录获取唯一标签的更好方法是什么?

这是我用来将其保存到数据库的代码。虽然它是用 Django 编写的,但显然这不是与 django 相关的问题。

class Note(models.Model):
    ...
    def save(self, *args, **kwargs):
        import random
        import string
        self.tag = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(36)])
        super(Note, self).save(*args, **kwargs)

【问题讨论】:

  • 您的方法看起来不错。我怀疑您在写入数据库时​​无意中创建了具有相同标签的重复记录。另一种方法是在创建记录之前检查数据库中是否存在标签。
  • 尝试使用uuid 而不是random
  • 感谢您的想法。我将编辑问题以显示我的数据库保存。真的不应该制作多条记录。而且,当我在数据库中看到它们时,这些记录似乎没有联系,也没有按时间或其他任何东西联系起来。
  • 接下来,我会将其设为UniqueField,但这仍然不能解释为什么会发生这种情况。嗯.....
  • 我只是模拟了 100 次不同的创建 2000 个标签,但在试验中我从未得到任何重复。我并不是说我不相信您的问题,而是问题不在于您生成标签的方式。我认为@gtlambert 的理论是正确的。您是否在其他任何地方保存到数据库?

标签: python django string random django-models


【解决方案1】:

你的方法的问题:

  1. 真正的随机性/加密很难,您应该尝试使用经过测试的现有解决方案,而不是实施自己的解决方案。
  2. 不能保证随机性 - 虽然“不太可能”,但没有什么可以阻止多次生成相同的字符串。

更好的解决方案是不要重新发明轮子,而是使用uuid 模块,这是生成唯一标识符的常用解决方案:

import uuid

tag = uuid.uuid1()

【讨论】:

  • 也没有什么能阻止相同的随机 uuid4 生成两次。我们相信这不太可能。 random.choice 使用了一个弱得多的RNG,它的熵源也弱得多,但它仍然不应该产生这么多重复。
  • @user2357112 虽然没有什么积极阻止它,uuid 包含 MAC 地址和当前时间。在家用机器上生成相同的 uuid4 两次,实际上是不可能的。
  • 我刚遇到这个。不知道这甚至是 Django 中的字段类型:docs.djangoproject.com/en/1.9/ref/models/fields/#uuidfield
  • @yurib:那是 UUID1。 UUID4 完全依赖于随机性。它有 4 位版本号、2 位保留位和 122 位随机位。 MAC 地址或时间戳不使用任何位。此外,在现代处理器速度下,UUID1 实现需要采取特殊对策以避免在同一台机器上生成两个具有相同时间戳的 UUID。
  • @user2357112 我对版本进行了更正。不过,我认为,无论版本如何,这都是比临时实现更好的生成唯一 ID 的方法。
【解决方案2】:

使用密码安全的PRNGrandom.SystemRandom()。它将使用您所在系统的 PRNG。

tag = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for n in xrange(36))

请注意,无需将此作为列表解析传递给join()

6236 个可能的组合,一个 65 位的数字,因此即使您考虑到 birthday paradox,重复也应该非常少。 p>

【讨论】:

    猜你喜欢
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 2013-07-14
    • 1970-01-01
    • 2019-10-02
    • 2010-12-07
    相关资源
    最近更新 更多