老齐教室

用4个简单的函数提升for循环

作者:Yong Cui, Ph.D.

翻译:老齐

与本文相关的图书推荐:《Python大学实用教程》

本书适合初学者使用,面向零基础学习者,详细讲述了Python语言的有关知识,并秉承面向对象这种主流开发思想。此外,书中配有大量的练习,学习者通过这些练习,更能体验到开发实践中的应用。

概要

在Python中,for循环经常被用于获得序列或者容器类的元素,比较让人熟知的就是针对可迭代对象的循环。for循环的基本语法如下:

1
2
for item in iterable:
# do something here

通常,可迭代对象包括序列(如:列表、元组和range对象)和容器类对象(如字典、集合),下面看一些示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> # 循环列表
>>> for item in [1, 2, 3]:
... pass
...
>>> # 循环元组
>>> for item in (1, 2, 3):
... pass
...
>>> # 循环range
>>> for item in range(3):
... pass
...
>>> # 循环字典
>>> for item in {0: 'a', 1: 'b', 2: 'c'}:
... pass
...
>>> # 循环集合
>>> for item in set([1, 2, 3]):
... pass
...

上面那些示例中的循环对象,都是基本的可迭代对象,此外,我们还可以用用内置函数,让for循环中的操作更优化,它们是:enumerate(), reversed(), sorted(), 和 zip(),在本文中,我将向您说明这些函数的用法。

enumerate()函数

第一个要介绍的内置函数是enumerate(iterable, start=0),它的参数是一个可迭代对象,返回枚举对象。参数start的默认值是0,也可以随意设置,它表示迭代开始编号。

例如,有一个列表,里面是公司员工的姓名,我们想给每个员工确定一个员工ID,可以使用enumerate()函数这样实现:

1
2
3
4
5
6
7
8
>>> employees = ['John', 'Danny', 'Jennifer']
>>>
>>> for id_number, name in enumerate(employees, start=30001):
... print(f"{name}'s employee ID #: {id_number}")
...
John's employee ID #: 30001
Danny's employee ID #: 30002
Jennifer's employee ID #: 30003

如上所示,我们创建了一个包含员工姓名的列表,它作为可迭代对象传给函数enumerate(),并且,start参数设置为30001,表示员工ID开始的编号。如你所见,每次循环,我们就得到了编号和列表中相应的元素。最后,根据我们的要求将结果打印出来。

reversed()函数

第二个内置函数reversed(seq),它以序列对象为参数(例如:元组和列表),返回一个反序的迭代器对象,本质上,这个函数的作用是将传入的序列对象中元素的排列顺序反序。

假设你的午餐如下面的列表所示,因为新冠病毒,就不要下馆子了。在接下来的一周内,你也不知道怎么变换吃的花样,于是,就干脆将列表中的食物反序吧。为此,我们可以使用reversed()函数。

1
2
3
4
5
6
7
8
9
10
>>> meals = ['pizza', 'hamberger', 'pasta', 'ramen', 'salad']
>>>
>>> for meal in reversed(meals):
... print(meal)
...
salad
ramen
pasta
hamberger
pizza

由上面代码可知,利用函数reversed(),得到了按变量meals中元素的相反顺序排列的食物。注意,对于list对象而言,也有一个reverse()方法,它能够原地将列表反序,即不会返回新的对象,或者说,只返回了None,这个操作不能用于for循环中,比如:

1
2
3
4
5
6
7
8
>>> for meal in meals.reverse():
... print(meal)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not iterable
>>> meals.reverse() is None
True

sorted()

第三个内置函数式sorted(iterable, *, key=None, reverse=False),其参数是可迭代对象,返回一个新的排序了的列表。需要注意两个关键词参数的使用,key,通过它可以指定一个含有一个参数的函数,用这个函数比较可迭代对象中的每个元素;reverse用于指定排序方式,如果为True表示反序。

假设一个员工列表,其中每个元素表示一个员工对象,每个员工对象包含名字和上一季度的绩效考核分数。我们需要根据绩效考核的分数对员工进行排序。下面的代码演示了实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> class Employee:
... def __init__(self, name, score):
... self.name = name
... self.score = score
...
>>> employee0 = Employee('John Smith', 95)
>>> employee1 = Employee('Mike Brown', 99)
>>> employee2 = Employee('Jennifer Thompson', 97)
>>> employees = [employee0, employee1, employee2]
>>>
>>> for employee in sorted(employees, key=lambda x: x.score, reverse=True):
... print(f'{employee.name} Score: {employee.score}')
...
Mike Brown Score: 99
Jennifer Thompson Score: 97
John Smith Score: 95

在上面的代码中,我们自定义了一个类Employee,用它来创建员工实例,并存储姓名和分数。然后创建3个员工实例,并将这三个员工实例存入一个列表中,这个列表将作为可迭代对象传给sorted()函数。注意:参数key的值,我们编写了一个lambda函数,它会对列表中每个员工实例的score属性进行比较。reverse参数的值设置为True,在输出结果中,会按照分数从大到小排序。

reversed()类似,列表对象有一个sort()方法,它能够对列表进行原地排序,所以,我们不能直接在for循环中用list.sort()方法。另外一个重要区别是,sorted()函数可以用任何可迭代对象为参数(比如:元组、字典),这使它在排序上的能力比sort()方法强悍,后者只能作为列表对象的方法。

zip()函数

第四个内置函数是zip(*iterables),可以用一个或多个可迭代对象作为参数,会返回一个迭代器对象,并且将参数中的可迭代对象的元素对应合并,合并后的元素以元组形式组合,如合并后的第1个元组中包含作为参数的每个可迭代对象中的第1个元素。

假设有两个整数作为元素的列表,我们需要相对应整数的乘积,就可以使用zip()函数来实现这个操作:

1
2
3
4
5
6
7
8
9
>>> numbers0 = [4, 5, 6]
>>> numbers1 = [11, 12, 13]
>>>
>>> for j, k in zip(numbers0, numbers1):
... print(f'{j} * {k} = {j*k}')
...
4 * 11 = 44
5 * 12 = 60
6 * 13 = 78

在上面的代码中,首先创建了两个列表numbers0numbers1,将它们传给zip()函数,返回的元组中包含了对应的数字。

一个需要注意的是,zip()函数返回的迭代器对象的长度,是以参数中最短的可迭代对象为准。例如下面的示例,两个字符串的长度不同,最后得到的迭代器对象只有3个元组,并且,必须用list()函数对迭代器对象进行转换,才能显示其具体内容。

1
2
3
4
>>> letters0 = 'abcde'
>>> letters1 = 'xyz'
>>> list(zip(letters0, letters1))
[('a', 'x'), ('b', 'y'), ('c', 'z')]

要点总结

本文主要探讨了for循环中使用的4个内置函数。这些函数的特点如下:

  • enumerate()函数允许创建循环的计数起点。
  • reversed()函数的作用主要是对序列进行反序。
  • sorted()函数能够对任何可迭代对象进行排序,并且可以灵活地指定任何排序关键词。
  • zip()函数主要用于组合可迭代对象中对应的元素,并返回一个迭代器对象。

原文链接:https://medium.com/swlh/level-up-for-loops-in-python-with-4-simple-functions-da01173a834c


专注于软件和AI的公众号

老齐教室

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

关注微信公众号,读文章、听课程,提升技能