Python 的 sum():Pythonic 的求和方法
摘要:Python 的内置函数 sum()是一种对数值列表求和的有效且 Pythonic 的方法。将多个数字相加是许多计算中常见的中间步骤,因此 sum()对于 Python 程序员来说是一个非常方便的工具。
本文分享自华为云社区《Python 的 sum():Pythonic的求和方法》,作者: Yuchuan 。
Python 的内置函数 sum()是一种对数值列表求和的有效且 Pythonic 的方法。将多个数字相加是许多计算中常见的中间步骤,因此 sum()对于 Python 程序员来说是一个非常方便的工具。
作为一个额外的和有趣的使用情况,您可以连接列表和元组使用 sum(),当你需要拼合列表的列表,可以很方便。
在本教程中,您将学习如何:
使用通用技术和工具手工对数值求和
使用 Pythonsum()高效地添加多个数值
拼接列表和元组与 sum()
使用 sum()接近普通求和问题
使用适当的值的参数中 sum()
之间做出选择 sum()和替代工具来总结和串连对象
这些知识将帮助您使用 sum()或其他替代和专用工具有效地处理和解决代码中的求和问题。
理解求和问题
将数值相加是编程中一个相当普遍的问题。例如,假设您有一个数字列表 [1, 2, 3, 4, 5] 并且想要将它们加在一起以计算它们的总和。使用标准算术,您将执行以下操作:
1 + 2 + 3 + 4 + 5 = 15
就数学而言,这个表达式非常简单。它会引导您完成一系列简短的加法,直到您找到所有数字的总和。
可以手动进行这个特定的计算,但想象一下其他一些不太可能的情况。如果您有一个特别长的数字列表,手动添加可能效率低下且容易出错。如果您甚至不知道列表中有多少项会发生什么?最后,想象一个场景,您需要添加的项目数量动态或不可预测地发生变化。
在这种情况下,无论您的数字列表是长列表还是短列表,Python 在解决求和问题方面都非常有用。
如果您想通过从头开始创建自己的解决方案来对数字求和,那么您可以尝试使用 for 循环:
>>>
在这里,您首先创建 total 并将其初始化为 0. 此变量用作累加器,您可以在其中存储中间结果,直到获得最终结果。循环通过使用增广赋值累加每个连续值来迭代 numbers 和更新。total
您还可以将 for 循环包装在函数中。这样,您可以为不同的列表重用代码:
>>>
在 sum_numbers()中,您将一个可迭代对象——特别是一个数值列表——作为参数,并返回输入列表中值的总和。如果输入列表为空,则函数返回 0。该 for 循环与您之前看到的相同。
您还可以使用递归代替迭代。递归是一种函数式编程技术,其中函数在其自己的定义中被调用。换句话说,递归函数在循环中调用自身:
>>>
当你定义一个递归函数时,你冒着陷入无限循环的风险。为了防止这种情况,您需要定义停止递归的基本情况和调用函数并启动隐式循环的递归情况。
在上面的例子中,基本情况意味着零长度列表的总和是 0。递归情况意味着总和是第一个值 numbers[0],加上其余值的总和 numbers[1:]。由于递归情况在每次迭代中使用较短的序列,因此您希望在 numbers 是零长度列表时遇到基本情况。作为最终结果,您将获得输入列表中所有项目的总和 numbers。
注意:在此示例中,如果您不检查空输入列表(您的基本情况),则 sum_numbers()永远不会遇到无限递归循环。当您的 numbers 列表长度达到 0 时,代码会尝试访问空列表中的项目,这会引发 IndexError 并中断循环。
使用这种实现,你永远不会从这个函数中得到一个总和。你 IndexError 每次都会得到一个。
在 Python 中对数字列表求和的另一种选择是使用 reduce()from functools。要获取数字列表的总和,您可以将任一 operator.add 或适当的 lambda 函数作为第一个参数传递给 reduce():
>>>
您可以致电 reduce()与减少或折叠,function 与一起 iterable 作为参数。然后 reduce()使用输入函数处理 iterable 并返回单个累积值。在第一个示例中,归约函数是 add(),它将两个数字相加。最终结果是 input 中数字的总和 iterable。作为一个缺点,reduce()提出了一个 TypeError 当你与一个空的调用它 iterable。
在第二个示例中,约简函数是一个 lambda 返回两个数字相加的函数。
由于像这样的求和在编程中很常见,因此每次需要对一些数字求和时编写一个新函数是大量重复性工作。此外, usingreduce()不是您可用的最易读的解决方案。
Python 提供了专门的内置函数来解决这个问题。该函数被方便地调用 sum()。由于它是一个内置函数,因此您可以直接在代码中使用它,而无需导入任何内容。
Python 入门 sum()
可读性是 Python 哲学背后最重要的原则之一。在对值列表求和时,可视化您要求循环执行的操作。您希望它遍历一些数字,将它们累加到一个中间变量中,然后返回最终和。但是,您可能可以想象一个不需要循环的更易读的求和版本。您希望 Python 取一些数字并将它们相加。
现在想想如何 reduce()求和。使用 reduce()可以说比基于循环的解决方案更不可读,更不直接。
这就是为什么将 Python2.3 添加 sum()为内置函数来为求和问题提供 Pythonic 解决方案的原因。Alex Martelli 贡献了这个函数,它现在是对值列表求和的首选语法:
>>>
哇!这很整洁,不是吗?它读起来像简单的英语,并清楚地传达您在输入列表上执行的操作。使用 sum()比 for 循环或 reduce()调用更具可读性。与 reduce(),当您提供空的可迭代对象时 sum()不会引发 a TypeError。相反,它可以理解地返回 0.
您可以 sum()使用以下两个参数进行调用:
1. iterable 是一个必需的参数,可以保存任何 Python 可迭代对象。可迭代对象通常包含数值,但也可以包含列表或元组。
2. start 是一个可选参数,可以保存一个初始值。然后将该值添加到最终结果中。它默认为 0.
在内部,从左到右 sum()添加 startplus 中的值 iterable。输入 iterable 中的值通常是数字,但您也可以使用列表和元组。可选参数 start 可以接受数字、列表或元组,具体取决于传递给 的内容 iterable。它不能带一个 string。
在以下两节中,您将了解 sum()在代码中使用的基础知识。
必需的参数: iterable
接受任何 Python iterable 作为它的第一个参数使得 sum()泛型、可重用和多态。由于此功能,您可以使用 sum()列表、元组、集合、range 对象和字典:
>>>
在所有这些示例中,sum()计算输入迭代中所有值的算术和,而不管它们的类型。在两个字典示例中,都调用 sum()返回输入字典键的总和。第一个示例默认对键求和,第二个示例由于.keys()调用输入字典而对键求和。
如果您的字典在其值中存储数字,并且您想对这些值而不是键进行求和,那么您可以.values()像.keys()示例中那样使用。
您还可以 sum()将列表推导式用作参数。这是一个计算一系列值的平方和的示例:
>>>
Python 2.4 向该语言添加了生成器表达式。同样,sum()当您使用生成器表达式作为参数时,按预期工作:
>>>
这个例子展示了解决求和问题的最 Pythonic 技术之一。它在一行代码中提供了一个优雅、可读且高效的解决方案。
可选参数: start
第二个可选参数 start 允许您提供一个值来初始化求和过程。当您需要按顺序处理累积值时,此参数很方便:
>>>
在这里,您提供初始值 100to start。净效果是 sum()将此值添加到输入可迭代中的值的累积总和中。请注意,您可以 start 作为位置参数或关键字参数提供。后一个选项更加明确和可读。
如果您没有为 提供值 start,则默认为 0。默认值 0 确保返回输入值总和的预期行为。
对数值求和
sum()的主要目的是提供一种 Pythonic 方式来将数值相加。到目前为止,您已经了解了如何使用该函数对整数求和。此外,可以使用 sum()任何其他数字 Python 类型,比如 float,complex,decimal.Decimal,和 fractions.Fraction。
以下是使用 sum()不同数字类型的值的几个示例:
>>>
在这里,您第一次使用 sum()与浮点数字。值得注意的是,当您使用特殊符号 inf 并 nan 在调用 float("inf")和 float("nan")中时函数的行为。第一个符号代表一个无限值,因此 sum()返回 inf。第二个符号代表 NaN(不是数字)值。由于您无法将数字与非数字相加,因此您会得到 nan 结果。
其他的例子总和 iterables 的 complex,Decimal 和 Fraction 数字。在所有情况下,sum()使用适当的数字类型返回结果累积总和。
连接序列
尽管 sum()主要用于对数值进行操作,但您也可以使用该函数来连接列表和元组等序列。为此,您需要为 提供适当的值 start:
>>>
在这些示例中,您使用 sum()连接列表和元组。这是一个有趣的功能,您可以使用它来展平列表列表或元组元组。这些示例工作的关键要求是为 选择适当的值 start。例如,如果要连接列表,则 start 需要持有一个列表。
在上面的示例中,sum()在内部执行连接操作,因此它仅适用于支持连接的序列类型,字符串除外:
>>>
当您尝试使用 sum()来连接字符串时,您会得到一个 TypeError. 正如异常消息所暗示的那样,您应该使用 str.join()来连接 Python 中的字符串。稍后,当您进入使用替代 sum()方法部分时,您将看到使用此方法的示例。
使用 Python 进行练习 sum()
到目前为止,您已经学习了使用 sum(). 您已经学习了如何使用此函数将数值相加,以及如何连接列表和元组等序列。
在本节中,您将查看更多有关何时以及如何 sum()在代码中使用的示例。通过这些实际示例,您将了解到当您执行需要查找一系列数字之和作为中间步骤的计算时,此内置函数非常方便。
您还将了解到这 sum()在您使用列表和元组时会很有帮助。您将看到的一个特殊示例是当您需要展平列表列表时。
计算累积和
您将编写的第一个示例与如何利用 start 参数对数值的累积列表求和有关。
假设您正在开发一个系统来管理给定产品在多个不同销售点的销售。每天,您都会收到来自每个销售点的销售单位报告。您需要系统地计算累计总和,以了解整个公司在一周内销售了多少件商品。要解决此问题,您可以使用 sum():
>>>
通过使用 start,您可以设置一个初始值来初始化总和,这允许您将连续单位添加到先前计算的小计中。在本周末,您将获得公司的销售单位总数。
计算样本的平均值
sum()的另一个实际用例是在进行进一步计算之前将其用作中间计算。例如,假设您需要计算数值样本的算术平均值。算术平均值,也称为平均值,是样本中值的总和除以值或数据点的数量。
如果你有样本 [2, 3, 4, 2, 3, 6, 4, 2]并且你想手工计算算术平均值,那么你可以解决这个操作:
(2 + 3 + 4 + 2 + 3 + 6 + 4 + 2) / 8 =3.25
如果您想通过使用 Python 加快速度,您可以将其分为两部分。此计算的第一部分,即您将数字相加,是 sum()的任务。运算的下一部分,即除以 8,使用样本中的数字计数。要计算您的除数,您可以使用 len():
>>>
在这里,调用 sum()计算样本中数据点的总和。接下来,您使用 len()来获取数据点的数量。最后,您执行所需的除法以计算样本的算术平均值。
在实践中,您可能希望将此代码转换为具有一些附加功能的函数,例如描述性名称和检查空样本:
>>>
在内部 average(),您首先检查输入样本是否有任何数据点。如果没有,那么你 ValueError 用一个描述性的消息来引发。在此示例中,您使用 walrus 运算符将数据点的数量存储在变量中,num_points 以便您无需 len()再次调用。该 return 语句计算样本的算术平均值,并将其发送回调用代码。
注意:计算数据样本的平均值是统计和数据分析中的常见操作。Python 标准库提供了一个方便的模块,称为 statistics 处理这些类型的计算。
在 statistics 模块中,您将找到一个名为 的函数 mean():
>>>
该 statistics.mean()函数的行为与 average()您之前编码的函数非常相似。当您 mean()使用数值样本进行调用时,您将获得输入数据的算术平均值。当您将空列表传递给 mean()时,您将获得一个 statistics.StatisticsError.请注意,当您 average()使用适当的样本调用时,您将获得所需的平均值。如果您 average()使用空样本调用,那么您会得到 ValueError 预期的结果。
求两个序列的点积
您可以使用的另一个问题 sum()是找到两个等长数值序列的点积。点积的代数和的产品在输入序列的每对值中的。例如,如果您有序列 (1, 2, 3) 和(4, 5, 6),那么您可以使用加法和乘法手动计算它们的点积:
1 × 4 + 2 × 5 + 3 × 6 = 32
要从输入序列中提取连续的值对,您可以使用 zip(). 然后您可以使用生成器表达式将每对值相乘。最后,sum()可以总结产品:
>>>
使用 zip(),您可以使用来自每个输入序列的值生成一个元组列表。生成器表达式循环遍历每个元组,同时将先前排列的连续值对乘以 zip()。最后一步是使用 将产品添加在一起 sum()。
上面示例中的代码有效。然而,点积是为等长的序列定义的,所以如果你提供不同长度的序列会发生什么?在这种情况下,zip()忽略最长序列中的额外值,这会导致不正确的结果。
为了处理这种可能性,您可以将调用包装 sum()在自定义函数中,并为输入序列的长度提供适当的检查:
>>>
这里,dot_product()将两个序列作为参数并返回它们对应的点积。如果输入序列的长度不同,则该函数会引发 a ValueError。
在自定义函数中嵌入功能允许您重用代码。它还使您有机会对函数进行描述性命名,以便用户仅通过阅读函数名称就知道该函数的作用。
展平列表列表
展平列表列表是 Python 中的一项常见任务。假设您有一个列表列表,需要将其展平为一个包含原始嵌套列表中所有项目的列表。您可以使用多种方法中的任何一种在 Python 中展平列表。例如,您可以使用 for 循环,如以下代码所示:
>>>
在 flatten_list()中,循环遍历 中包含的所有嵌套列表 a_list。然后它 flat 使用增强赋值操作 ( +=)将它们连接起来。结果,您会得到一个平面列表,其中包含原始嵌套列表中的所有项目。
但是坚持住!您已经 sum()在本教程中学习了如何使用来连接序列。您可以使用该功能来像上面的示例中那样展平列表列表吗?是的!就是这样:
>>>
那很快!一行代码,matrix 现在是一个平面列表。但是,使用 sum()似乎不是最快的解决方案。
任何暗示串联的解决方案的一个重要缺点是,在幕后,每个中间步骤都会创建一个新列表。这在内存使用方面可能非常浪费。最终返回的列表只是在每一轮连接中创建的所有列表中最近创建的列表。使用列表推导式可确保您只创建和返回一个列表:
>>>
这个新版本 flatten_list()在内存使用方面效率更高,浪费更少。然而,嵌套的理解可能难以阅读和理解。
使用.append()可能是扁平化列表列表最易读和 Pythonic 的方式:
>>>
在这个版本中 flatten_list(),一个人阅读你的代码可以看出,功能遍历每个 sublist 在 a_list。在第一个
for 循环中,它遍历每个 iteminsublist 以最终 flat 使用.append(). 就像前面的推导一样,这个解决方案在这个过程中只创建了一个列表。这种解决方案的一个优点是它的可读性很强。
使用替代品 sum()
正如您已经了解到的,sum()一般来说,对于处理数值很有帮助。但是,在处理浮点数时,Python 提供了一种替代工具。在 math 中,您会找到一个名为的函数 fsum(),它可以帮助您提高浮点计算的总体精度。
您可能有一项任务,您希望连接或链接多个可迭代对象,以便您可以将它们作为一个整体处理。对于这种情况,您可以查看 itertools 模块的 function chain()。
您可能还有一个要连接字符串列表的任务。您在本教程中了解到,无法 sum()用于连接字符串。这个函数不是为字符串连接而构建的。最 Pythonic 的替代方法是使用 str.join().
对浮点数求和:math.fsum()
如果您的代码不断使用 对浮点数求和 sum(),那么您应该考虑 math.fsum()改用 。此函数比 更仔细地执行浮点计算 sum(),从而提高计算精度。根据其文档,fsum()“通过跟踪多个中间部分和来避免精度损失。” 该文档提供了以下示例:
>>>
使用 fsum(),您可以获得更精确的结果。但是,您应该注意这 fsum()并不能解决浮点运算中的表示错误。以下示例揭示了此限制:
>>>
在这些示例中,两个函数返回相同的结果。这是因为不可能准确地表示这两个值 0.1 和 0.2 二进制浮点数:
>>>
sum()但是,与 不同的是,fsum()当您将非常大和非常小的数字相加时,可以帮助您减少浮点错误传播:
>>>
哇!第二个例子非常令人惊讶并且完全失败 sum()。使用 sum(),您将得到 0.0 结果。这与 20000.0 的正确结果相去甚远,正如您所得到的 fsum()。
连接可迭代对象 itertools.chain()
如果您正在寻找一个方便的工具来连接或链接一系列可迭代对象,请考虑使用 chain()from itertools。此函数可以采用多个迭代器并构建一个迭代器,该迭代器从第一个、第二个中产生项目,依此类推,直到耗尽所有输入迭代:
>>>
当您调用 chain()时,您会从输入可迭代对象中获得项目的迭代器。在本例中,您可以 numbers 使用访问连续的项目 next()。如果你想使用一个列表,那么你可以使用它 list()来使用迭代器并返回一个常规的 Python 列表。
chain() 在 Python 中展平列表列表也是一个不错的选择:
>>>
要使用 扁平化列表列表 chain(),您需要使用可迭代解包运算符( *)。此运算符解包所有输入可迭代对象,以便 chain()可以使用它们并生成相应的迭代器。最后一步是调用 list()以构建所需的平面列表。
连接字符串 str.join()
正如您已经看到的,sum()不连接或连接字符串。如果您需要这样做,那么 Python 中可用的首选和最快的工具是 str.join(). 此方法将一系列字符串作为参数并返回一个新的连接字符串:
>>>
使用.join()是连接字符串的最有效和 Pythonic 的方式。在这里,您使用字符串列表作为参数并从输入构建单个字符串。请注意,.join()在连接期间使用您调用方法的字符串作为分隔符。在此示例中,您调用.join()由单个空格字符 ( "")组成的字符串,因此原始字符串 fromgreeting 在最终字符串中由空格分隔。
结论
您现在可以使用 Python 的内置函数 sum()将多个数值相加。此函数提供了一种高效、可读且 Pythonic 的方法来解决代码中的求和问题。如果您正在处理需要对数值求和的数学计算,那么它 sum()可以成为您的救星。
在本教程中,您学习了如何:
使用通用技术和工具对数值求和
使用 Python 有效地添加多个数值 sum()
使用连接序列 sum()
使用 sum()接近普通求和问题
使用适当的值的 iterable 和 start 争论中 sum()
之间做出选择 sum()和替代工具来总结和串连对象
有了这些知识,您现在可以以 Pythonic、可读且高效的方式将多个数值相加。
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/db47ee515753b665c0ba2e36e】。文章转载请联系作者。
评论