Python 懒惰字典评估

4 投票
3 回答
4541 浏览
提问于 2025-04-16 02:42

一些Python的支持者会说,Python没有switch语句的原因是它有字典。那么...我该如何利用字典来解决这个问题呢?

这个问题是,所有的值在根据输入进行评估时都会抛出异常。

这里有一个简单的例子,展示了一个类,它可以存储一个数字或一组数字,并提供乘法功能。

class MyClass(object):

    def __init__(self, value):
        self._value = value

    def __mul__(self, other):
        return {
            (False, False): self._value * other._value                        ,
            (False, True ): [self._value * o for o in other._value]           ,
            (True , False): [v * other._value for v in self._value]           ,
            (True , True ): [v * o for v, o in zip(self._value, other._value)],
        }[(isinstance(self._value, (tuple, list)), isinstance(other._value, (tuple, list)))]

    def __str__(self):
        return repr(self._value)
    __repr__ = __str__



>>> x = MyClass(2.0)
>>> y = MyClass([3.0, 4.0, 5.0])
>>> print x
2.0
>>> print y
[3.0, 4.0, 5.0]
>>> print x * y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __mul__
TypeError: can't multiply sequence by non-int of type 'float'

我可以通过在每个值前面加上“lambda : ”来解决这个问题,然后在查找字典后调用这个lambda函数……“}(isinsta ...)”

有没有更好的方法呢?

3 个回答

1

我想到两种方法:

  • 使用一些 if 语句。对于只有四种 TrueFalse 的组合来说,这样做还算可以。根据我的观察,在 Python 代码中,连续使用 if ... elif ... elif ... 的写法是比较常见的。

  • 一次性创建一个字典(作为类的字段,而不是实例的字段),然后把(lambda)函数存放在里面。这种方法比前一种更好扩展,对于很多选项来说速度也更快(虽然我不知道“很多”具体指多少)。

1

我觉得这里最重要的是可读性。
你展示的那种字典查找方式确实不容易理解,因此也不容易维护。

在我看来,写软件的主要目标应该是让代码易于阅读;所以我会选择用一系列的if/elif语句来明确比较这两个值(而不是使用类型映射)。如果之后发现性能有问题,再考虑其他解决方案(比如用字典查找函数)也不迟。

4

是的,可以为这些不同的选项定义一些小的匿名函数(也叫lambda函数):

    def __mul__(self, other): 
        scalar_times_scalar = lambda x,y: x*y
        scalar_times_seq    = lambda x,y: [x*y_i for y_i in y]
        seq_times_scalar    = lambda x,y: scalar_times_seq(y,x)
        seq_times_seq       = lambda x,y: [x_i*y_i for x_i,y_i in zip(x,y)]
        self_is_seq, other_is_seq = (isinstance(ob._value,(tuple, list)) 
                                                    for ob in (self, other))
        fn = {
            (False, False): scalar_times_scalar, 
            (False, True ): scalar_times_seq, 
            (True , False): seq_times_scalar, 
            (True , True ): seq_times_seq, 
            }[(self_is_seq, other_is_seq)] 
        return fn(self._value, other._value)

当然,理想情况下,你应该只在类或模块的范围内定义这些匿名函数一次。我在这里把它们放在__mul__方法里,是为了方便大家参考。

撰写回答