【问题标题】:Why is some code Deterministic in Python2 and Non-Deterministic in Python 3?为什么某些代码在 Python2 中是确定性的,而在 Python 3 中是非确定性的?
【发布时间】:2013-11-21 05:48:18
【问题描述】:

我正在尝试编写一个脚本来计算一个短字符串或“kmer”的所有可能的模糊字符串匹配匹配,而在 Python 2.7.X 中工作的相同代码给了我一个不确定的答案使用 Python 3.3.X,我不知道为什么。

我在我的代码中遍历字典、itertools.product 和 itertools.combinations,但我遍历所有这些以完成,没有中断或继续。此外,我将所有结果存储在单独的字典中,而不是我正在迭代的字典中。简而言之 - 我没有犯任何对我来说很明显的错误,那么为什么 Python2 和 Python3 之间的行为不同?

下面是稍微简化的示例代码:

import itertools

def find_best_fuzzy_kmer( kmers ):
    for kmer, value in kmers.items():
        for similar_kmer in permute_string( kmer, m ):
            # Tabulate Kmer

def permute_string( query, m ):
    query_list = list(query)
    output = set() # hold output
    for i in range(m+1):
        # pre-calculate the possible combinations of new bases
        base_combinations = list(itertools.product('AGCT', repeat=i))
        # for each combination `idx` in idxs, replace str[idx]
        for positions in itertools.combinations(range(len(query_list)), i):
            for bases in base_combinations:
                # Generate Permutations and add to output
    return output

【问题讨论】:

  • 请给出一个有问题的输入的具体例子,以及你在两个 Python 下得到的输出。 “非确定性”对您来说可能很清楚,但我们不知道您的意思 ;-)
  • 我的猜测是它与字典和集合有关。字典是一组键:值对。集合是无序的,这意味着您不能依赖实现中对象的顺序。我在想的是,python 3 以与 python 2 不同的方式实现这两个东西。如果您的实现依赖于 dict 或 set 的顺序,那么您不应该使用它们。
  • “我没有犯任何对我来说很明显的错误” 现在你知道了:迭代字典并假设它在迭代顺序上有 any 保证 是一个明显的错误。如果您想对订单进行保证,请使用OrderedDict 或仅使用list(the_dict.items())(顺便说一下,它使用的内存比OrderedDict 少)。
  • @Bakuriu,请注意list(the_dict.items()) 不会强制执行命令; sorted(the_dict.items()) 当然可以。
  • @TimPeters 是的,我的意思是sorted。我不知道为什么我写了一个普通的list...

标签: python string python-3.x bioinformatics non-deterministic


【解决方案1】:

如果“非确定性”是指字典键出现的顺序(当您遍历字典时)从运行到运行发生变化,并且字典键是字符串,请这样说.那我可以帮忙。但到目前为止,你还没有说这些;-)

假设这就是问题所在,这里有一个小程序:

d = dict((L, i) for i, L in enumerate('abcd'))
print(d)

4 的输出在 Python 3.3.2 下运行:

{'d': 3, 'a': 0, 'c': 2, 'b': 1}
{'d': 3, 'b': 1, 'c': 2, 'a': 0}
{'d': 3, 'a': 0, 'b': 1, 'c': 2}
{'a': 0, 'b': 1, 'c': 2, 'd': 3}

python -h 输出的这部分暗示了原因:

Other environment variables:
...
PYTHONHASHSEED: if this variable is set to 'random', a random value is used
   to seed the hashes of str, bytes and datetime objects.  It can also be
   set to an integer in the range [0,4294967295] to get hash values with a
   predictable seed.

这是一个半生不熟的“安全修复”,旨在帮助防止基于构建旨在引发二次时间行为的 dict 输入的 DOS 攻击。 “随机”是 Python3 中的默认值。

您可以通过将 envar PYTHONHASHSEED 设置为整数来关闭它(您的选择 - 如果您不关心,请选择 0)。然后使用字符串键迭代 dict 将在运行中以相同的顺序生成它们。

正如@AlcariTheMad 在评论中所说,您可以通过python -R ...启用 Python 2 下的 Python3 默认行为。

【讨论】:

  • @thefourtheye,“控制”大多是虚幻的——关于dict迭代顺序仍然没有定义。所有这些技巧提供的是一致的跨运行顺序,前提是 dict 在运行中以完全相同的方式构建(相同的键插入和删除序列)。
  • 而且,这可能不言而喻,但哈希随机化也适用于 set 对象。
  • 而 Python 3.4 通过切换到基于加密的哈希来完成远程 DOS 修复:)
猜你喜欢
  • 1970-01-01
  • 2016-05-14
  • 2013-07-04
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 2011-04-03
  • 1970-01-01
相关资源
最近更新 更多