3

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。我猜这假设了某种迭代字典的评估顺序。

现在查看Python 团队最新发布公告的以下摘录,了解最新版本的分支 2.6、2.7、3.1 和 3.2:

哈希随机化导致 dicts 和 set 的迭代顺序是不可预测的,并且在 Python 运行中会有所不同。Python 从未保证 dict 或 set 中键的迭代顺序,建议应用程序永远不要依赖它。从历史上看,dict 迭代顺序在不同版本之间并没有经常改变,并且在 Python 的连续执行之间始终保持一致。因此,一些现有的应用程序可能依赖于 dict 或 set 排序。

这是否意味着不再可能使用 dicts 作为 switch 调用?或者也许我应该使用任何其他类(比如OrderedDict或其他东西)?或者也许我完全关闭了,它根本不应该影响这个?

4

8 回答 8

6

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

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

字典查找没有迭代。

于 2012-04-17T08:00:54.393 回答
5

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

也就是说,我发现你的技术比简单的if..elif链更晦涩,效率也更低(构建一个新的字典并不便宜)。

于 2012-04-17T08:00:56.203 回答
3

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

于 2012-04-17T08:00:16.730 回答
2

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

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

return ( a if a > 0  else
         0 if a == 0 else
        -a)
于 2012-04-17T08:06:33.113 回答
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

您似乎误解了您的代码真正在做什么的事实应该清楚地表明您做错了什么。

于 2012-04-17T08:10:13.817 回答
1

This is a very dirty code, the line with the dictionary takes minutes to read (although I work with Python for 3 years), and this will be very hard to debug. The next developer (read: yourself in half a year) will not be able to read this.

switch construct can be replaced with a dict of callbacks, if you need them:

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

If you need only True/False, you don't need any structure:

return one_func() if check else another_func()

In many cases, switch can be replaced with a chain of if ... return:

if check:
    return one_func()

return another_func() if another_check else third_func()

All these are much more readable and debuggable.

于 2012-04-17T08:04:29.960 回答
0

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

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

你为什么不试试:

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

和:

switch[variable]()
于 2012-04-17T08:01:40.960 回答
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永远不会被评估(即使你没有return超过它也不会被评估)。您的字典每次都需要评估您给它的每个键作为条件。尝试使用字典调度而不是链式ifs 的唯一原因是效率,但是在键不是恒定的并且整个 dict 可预计算的情况下,您可能会输得很惨。

于 2012-04-17T08:07:41.303 回答