Python懒字典求值

4
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 ...)"

是否有更好的方法?


1
从面向对象的角度来看,接受任何类型的值的方法是最糟糕的事情之一,这就是为什么代码看起来如此丑陋的原因。 - Jochen Ritzel
3个回答

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)

理想情况下,您当然会在类或模块范围内仅定义这些lambda函数。我在这里只是为了方便参考而在__mul__方法中展示它们。

1

我可以想到两种方法:

  • 使用一些if语句。对于仅有四种TrueFalse的组合,这并不糟糕。从我所见过的Python代码来看,if ... elif ... elif ...子句的序列并不罕见。

  • 创建字典一次(作为类字段而不是实例字段),并在其中存储(lambda)函数。这比前一种方法更具可扩展性,并且对于许多选项来说速度更快(尽管我不知道“许多”值的大小)。


1
我认为这里的重点是可读性。
像你展示的字典查找确实很难阅读,因此也难以维护。

在我看来,编写软件的主要目标应该是可读性;出于这个原因,我会选择使用一组 if/elif 明确比较两个值(而不是为类型建立映射);然后,如果测量显示存在性能问题,可以尝试其他解决方案(如使用函数进行字典查找)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接