5.Loops and List Comprehensions

Loops

循环是一种重复执行某些代码的方法。

[1]

planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
for planet in planets:
    print(planet, end=' ') # print all on same line
Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune 

注意for循环的简单性:我们指定我们想要使用的变量,我们想要循环的序列,并使用“in”关键字以直观和可读的方式将它们链接在一起。

“in”右侧的对象可以是支持迭代的任何对象。 基本上,如果它可以被认为是一个序列或事物的集合,可以循环它。 除了列表,我们也可以迭代元组中的元素:

[2]

multiplicands = (2, 2, 2, 3, 3, 5)
product = 1
for mult in multiplicands:
    product = product * mult
product
360

甚至还可以迭代字符串中的每个字母:

[3]

s = 'steganograpHy is the practicE of conceaLing a file, message, image, or video within another fiLe, message, image, Or video.'
msg = ''
# print all the uppercase letters in s, one at a time
for char in s:
    if char.isupper():
        print(char, end='')     
HELLO

range()

range()是一个返回数字序列的函数。 事实证明,编写循环非常有用。

例如,如果我们想重复一些动作5次:

[4]

for i in range(5):
    print("Doing important work. i =", i)
Doing important work. i = 0
Doing important work. i = 1
Doing important work. i = 2
Doing important work. i = 3
Doing important work. i = 4

你可能认为range(5)返回列表[] 1,  2, 3,  4,  5] ,真是情况有点复杂。

[5]

r = range(5)
r
range(0, 5)

range返回“range object”。 它的行为很像列表(它是可迭代的),但不具备所有相同的功能。 正如我们在上一个教程中看到的那样,我们可以在像r这样的对象上调用help()来查看该对象的Python文档,包括它的所有方法。 

[6]

help(range)

就像我们可以使用int(),float()和bool()将对象转换为另一种类型一样,我们可以使用list()将类似列表的东西转换为列表,这表示更熟悉(和有用) 的表示:

[7]

list(range(5))
[0, 1, 2, 3, 4]

请注意,范围从零开始,按照惯例,范围的顶部 不包括在输出中。 range(5)给出0到5但不包括5的数字。

这可能看起来像是一种奇怪的方式,但文档(通过help(range))提到的原因是:

range(4)产生0,1,2,3。这些正是4个元素列表的有效索引。
因此对于任何列表L,for i in range(len(L)):将迭代其所有有效索引。

[8]

nums = [1, 2, 4, 8, 16]
for i in range(len(nums)):
    nums[i] = nums[i] * 2
nums
[2, 4, 8, 16, 32]

这是通过索引迭代列表或其他序列的经典方法。

另外:for i in range(len(L)):类似于其他语言中的for (int i = 0; i < L.length; i++)

enumerate

for foo in x 通过元素循环遍历列表,而for i in range(len(x))通过索引循环遍历列表。 如果你想两个都做怎么办?

输入枚举函数,这是Python隐藏的宝石之一:

[9]

def double_odds(nums):
    for i, num in enumerate(nums):
        if num % 2 == 1:
            nums[i] = num * 2

x = list(range(10))
double_odds(x)
x
[0, 2, 2, 6, 4, 10, 6, 14, 8, 18]

给定一个列表,枚举返回一个对象,该对象通过列表的值和索引进行迭代。

(与range()函数一样,它返回一个可迭代对象。要将其内容作为列表查看,我们可以在其上调用list()。)

[10]

list(enumerate(['a', 'b']))

[(0, 'a'), (1, 'b')]

我们可以看到,我们迭代的东西是元组。 这有助于解释for i,num语法。 我们正在“解包”元组,就像上一个教程中的示例一样:

[11]

x = 0.125
numerator, denominator = x.as_integer_ratio()

我们可以在迭代元组集合时使用这种解包语法。

[12]

nums = [
    ('one', 1, 'I'),
    ('two', 2, 'II'),
    ('three', 3, 'III'),
    ('four', 4, 'IV'),
]

for word, integer, roman_numeral in nums:
    print(integer, word, roman_numeral, sep=' = ', end='; ')
1 = one = I; 2 = two = II; 3 = three = III; 4 = four = IV; 

这与下面的代码等价:

[13]

for tup in nums:
    word = tup[0]
    integer = tup[1]
    roman_numeral = tup[2]
    print(integer, word, roman_numeral, sep=' = ', end='; ')
1 = one = I; 2 = two = II; 3 = three = III; 4 = four = IV; 

while loops

Python中另一类循环是while循环:

[14]

i = 0
while i < 10:
    print(i, end=' ')
    i += 1
0 1 2 3 4 5 6 7 8 9

while循环的参数被计算为布尔语句,并且直到语句求值为False时停止循环。

List comprehensions

列表解析是Python中最受欢迎和独特的功能之一,理解它的最简单的方式就是看一下例子:

[15]

squares = [n**2 for n in range(10)]
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

这里有一个不用列表解析的例子,效果是一样的:

[16]

squares = []
for n in range(10):
    squares.append(n**2)
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

我们也增加if条件:

[17]

short_planets = [planet for planet in planets if len(planet) < 6]
short_planets
['Venus', 'Earth', 'Mars']

(如果您熟悉SQL,可能会将其视为“WHERE”子句)

以下是使用if条件进行过滤并对循环变量应用某些变换的示例:

[18]

# str.upper() returns an all-caps version of a string
loud_short_planets = [planet.upper() + '!' for planet in planets if len(planet) < 6]
loud_short_planets
['VENUS!', 'EARTH!', 'MARS!']

人们通常把这些写在一行里,但是如果分成3行来写,结果会变得很清晰:

[19]

[
    planet.upper() + '!' 
    for planet in planets 
    if len(planet) < 6
]

['VENUS!', 'EARTH!', 'MARS!']

继续SQL类比,您可以将这三行视为SELECT,FROM和WHERE

左边的表达式在技术上不必涉及循环变量(尽管它不是很常见)。 您认为以下表达式将做什么? 

[20]

[32 for planet in planets]

列表解析与我们看到的一些函数(如min,max,sum,len和sorted)相结合,可以为一些问题提供一些令人印象深刻的单行解决方案,否则这些问题需要几行代码。

例如,最后一个练习包括一个脑力激荡器,要求你编写一个函数来计算列表中的负数,而不使用循环(或我们没有看到的任何其他语法)。 现在我们可以解决问题,因为我们的武器库中有循环:

[21]

def count_negatives(nums):
    """Return the number of negative numbers in the given list.
    
    >>> count_negatives([5, -1, -2, 0, 3])
    2
    """
    n_negative = 0
    for num in nums:
        if num < 0:
            n_negative = n_negative + 1
    return n_negative

这有一个使用列表解析的办法:

[22]

def count_negatives(nums):
    return len([num for num in nums if num < 0])

很好吧?

好吧,如果我们关心的是最小化代码的长度,那么第三种解决方案仍然更好!

[23]

def count_negatives(nums):
    # Reminder: in the "booleans and conditionals" exercises, we learned about a quirk of 
    # Python where it calculates something like True + True + False + True to be equal to 3.
    return sum([num < 0 for num in nums])

这些解决方案中哪一个是“最好的”完全是主观的。 使用较少的代码解决问题总是很好,但值得记住以下来自The Zen of Python的内容:

  • 可读性很重要。
  • 显式优于隐式。

count_negatives的最后一个定义可能是最短的,但阅读代码的其他人是否理解它是如何工作的?

编写Pythonic代码并不意味着永远不会使用for循环!

Your turn!

转到练习笔记本,进行循环和列表解析的练习。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值