【问题标题】:Avoiding Side Effects in List Comprehension避免列表理解中的副作用
【发布时间】:2020-05-28 23:28:10
【问题描述】:

处理字典列表和避免副作用(什么是副作用)的最 Pythonic 和最有效的方法是什么?

更具体地说:为什么以下代码会生成生成器对象,而几乎任何其他类似的代码都会生成所需的输出?

print(sum(dictionary[site] for site in dictionary) for dictionary in listofdictionaries)

一些背景

我从摆弄**kwargs 开始,并生成了我认为非常糟糕的代码。

def testing(**kwargs):
    mysum = 0
    for kw in kwargs:
        mysum += kwargs[kw]
    print(mysum)


listofdictionaries = [{"site1": 1, "room1": 2, "day1": 3}, {"site2": 4, "room2": 5, "day2": 6}]

for dictionary in listofdictionaries:
    testing(**dictionary)

我查看了 Data Structures Document 包括 List Comprehension 并找到了实现相同输出的更好方法:

listofdictionaries = [{"site1": 1, "room1": 2, "day1": 3}, {"site2": 4, "room2": 5, "day2": 6}]
for dictionary in listofdictionaries:
    mysum = 0
    for value in dictionary:
        mysum += dictionary[value]
    print(mysum)

然后变得有点聪明,并缩短了一点:

for dictionary in listofdictionaries:
    print(sum(dictionary[value] for value in dictionary))

我真的没有兴趣为了使它成为单线而使其成为单线,但是在阅读了 Stack Overflow 上无数关于避免“副作用”的列表理解帖子之后,我觉得可能有采取这一措施的额外步骤。也许我不明白什么是副作用。

无论如何,这些中的每一个都应该导致输出:

6
15

【问题讨论】:

  • 您的代码没有副作用。副作用就像改变数据结构、分配给变量、打印到标准输出或写入文件。
  • 因此,例如,您的 for 循环使用副作用,mysum += dictionary[value] 修改了 mysum 变量。但这没关系,python 是一种按设计以这种方式工作的命令式语言。列表推导及其表亲是函数式编程结构,旨在表达映射/过滤操作,这就是为什么它们应该没有副作用。

标签: python python-3.x list-comprehension nested-loops


【解决方案1】:

您的具体问题仅打印由生成器表达式形成的实际生成器对象的表示,即这个-

(sum(dictionary[site] for site in dictionary) for dictionary in listofdictionaries)

有关更多详细信息,请参阅有关打印生成器的此答案- https://stackoverflow.com/a/44616115

对于这个例子,你最好使用列表推导式,例如

print([sum(dictionary.values()) for dictionary in listofdictionaries])

你可以先解压生成器来打印它,但在这个例子中,它看起来不太可读且效率较低-

print(*(sum(dictionary.values()) for dictionary in listofdictionaries))

副作用可能是一个相当广泛的术语-https://en.wikipedia.org/wiki/Side_effect_(computer_science),但根据前面的答案,您不会使用这些方法以任何方式修改您的字典,因此没有副作用。

【讨论】:

    【解决方案2】:

    你可以通过添加一个函数来计算一个字典的总和,并使用这样的列表理解:

    def dict_sum(dictionary):
        mysum = 0
        for value in dictionary:
            mysum += dictionary[value]
        return mysum
    
    print([dict_sum(dictionary) for dictionary in listofdictionaries])
    >> [6, 15]
    

    但是,您的双班轮不应该有任何副作用。我不知道你指的是什么帖子,但如果你不修改列表,那么你应该没问题,它们应该在最后保持不变。

    【讨论】:

      猜你喜欢
      • 2021-11-16
      • 2021-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-30
      相关资源
      最近更新 更多