在Python 2.7.3中使用字典作为switch语句

时间:2012-04-17 07:55:20

标签: python switch-statement dictionary

我喜欢使用字典作为switch语句的一种形式,通过设置布尔值作为键。例如:

>>> def f(a):
...      return {True: -a, a==0: 0, a > 0: a}[True]
... 
>>> f(-3)
3
>>> f(3)
3
>>> f(0)
0

密钥True用作else / default个案,只有在True未评估其他密钥时才会返回。我猜这是假设迭代字典的某种评估顺序。

现在查看最新版release announcement from the Python team的以下摘录,了解分支机构2.6,2.7,3.1和3.2的最新版本:

  

哈希随机化导致dicts和sets的迭代顺序为   Python运行中不可预测且不同。 Python从来没有   保证字典或集合中的键的迭代顺序和应用程序   建议永远不要依赖它。历史上,dict迭代顺序   在各个版本中并没有经常发生变化,而且一直存在   连续执行Python之间的一致性。因此,一些   现有的应用程序可能依赖于字典或设置顺序。

这是否意味着使用dicts作为切换呼叫将不再可能?或者也许我应该使用任何其他类(如OrderedDict或其他)?或者也许我完全不在了,它根本不应该影响这个?

8 个答案:

答案 0 :(得分:6)

您误解了此代码的工作原理。

您的词典只有两个键:TrueFalseTrue键可能存在多个冲突值,但在字典初始化时会得到解决。

字典查找没有迭代。

答案 1 :(得分:5)

哈希随机化不会影响您的应用程序。它应该只影响依赖于字典中键的迭代顺序的应​​用程序。

那就是说,我发现你的技术比简单的if..elif链更加模糊,效率也更低(建立一个新的dict并不便宜)。

答案 2 :(得分:3)

使用字典散列条件的方式不会受到排序的影响。您正在严格使用键来访问字典,并且排序对您来说并不重要,因为您没有迭代键/值。因此,您对字典的特定用法不受Python字典哈希随机化的影响。

答案 3 :(得分:2)

假设字典按从左到右的顺序构建,这可能仍然有效。关于无序迭代的要点是关于构建字典后的遍历,而不是构造过程本身,并且无论如何,你正在索引它,而不是迭代它。

但坦率地说,依靠这种行为并不是一个好主意。它很脆弱,因为它依赖于假定的行为(虽然可能在规范中有某些东西可以保证这一点)而且非常混乱,这在很大程度上是因为案件的评估顺序实际上是从右到左(即,正确的 - 最真实的案例胜利)。一个更易于理解的解决方案如下:

return ( a if a > 0  else
         0 if a == 0 else
        -a)

答案 4 :(得分:2)

首先,要意识到您的代码或多或少等同于:

def f(a):
    d = {}
    d[True] = -a
    d[a==0] = 0
    d[a>0] = a
    return d[True]

考虑到这一点,回答你的问题变得显而易见。

为什么你会用这种模糊的语法而不是更简单的方法呢? 甚至这个更具可读性:

def f(a):
    return a if a > 0 else 0 if a == 0 else -a

你似乎误解了你的代码实际上在做什么这一事实应该是你做错事的一个明确迹象。

答案 5 :(得分:1)

这是一个非常脏的代码,带字典的行需要几分钟才能阅读(尽管我使用Python 3年),这将很难调试。下一位开发人员(阅读:半年内自己)将无法阅读此内容。

如果需要,可以用回调函数替换

switch构造:

 {value1: one_func, value2: another_func, value3: third_func}

如果您只需要True / False,则不需要任何结构:

return one_func() if check else another_func()

在许多情况下,可以使用if ... return:

链替换开关
if check:
    return one_func()

return another_func() if another_check else third_func()

所有这些都更具可读性和可调试性。

答案 6 :(得分:0)

您没有在示例中使用迭代,因此您的代码是安全的。

但是,您的解决方案有点奇怪,boolean因为密钥不太可读。

为什么不尝试:

switch = {
   choice1: func1
   choice1: func2
   ...
}

switch[variable]()

答案 7 :(得分:0)

如果您正在执行以下操作,那只会影响您:

 mydict.values()[0]

依靠这一点始终是相同的价值。你引用的文档说这不能保证会发生。

但是,您的代码有一个需要考虑的问题,那就是与短路有关。如果你这样做:

if a == 0:
     return 0
elif a > 0:
     return a
else:
     return -a

或者,更简洁(但可以说是不太可读)return 0 if a == 0 else a if a > 0 else -a,a是0,那么a > 0永远不会被评估(即使你不{{1}也不会} 它上面)。您的词典需要每次评估您给出的每个键作为条件。尝试字典调度而不是链接return的唯一原因是效率,但是如果键不是常量并且整个字典可以预先计算,那么你可能会输掉很多。