条件和循环 - QLGQ/learning-python GitHub Wiki

条件表达式(三元操作符)

X if C else Y
C是条件表达式;X是C为True时的结果,Y是C为 False时的结果。

xrange()

xrange()类似range(),不过当你有一个很大的范围列表时,xrange()可能更合适,因为它不会在内存里创建列表的完整拷贝。它只被用在for循环中,在for循环外使用它没有意义。

与序列相关的内建函数

sorted()、reversed()、enumerate()、zip()
sorted()和zip()返回一个序列(列表),而另外两个函数reversed()和enumerate()返回迭代器(类似序列)。
zip():
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

continue

当遇到 continue语句 时,程序会终止当前循环,并忽略剩余的语句,然后回到循环的顶端。在开始下一次迭代前,如果是条件循环,我们将验证条件表达式;如果是迭代循环,我们将验证是否还有元素可以迭代。只有在验证成功的情况下,我们才会开始下一次迭代。continue在开始下一次循环前要满足一些先决条件,否则循环会正常结束。

valid = False
count = 3
while count > 0:
    input = raw_input("enter password")
    # check for valid passwd
    for eachPasswd in passwdList:
        if input == eachPasswd:
            valid = True
            break
    if not valid:        # (or valid == 0)
        print "invalid input"
        count -= 1
        continue
    else:
        break

else语句

在C(以及大多其他语言中),你不会在条件语句范围外发现else语句,但Python不同,你可以在while和for循环中使用else语句。它们是怎么工作的呢?在循环中使用时,else子句只在循环完成后执行,也就是说break语句也会跳过else语句

使用迭代器

序列

序列会自动地产生它们自己的迭代器,所以一个for循环:

for i in seq:
    do_something_to(i)

实际上是这样工作的:

fetch = iter(seq)
while True:
    try:
        i = fetch.next()
    except StopIteration:
        break
    do_something_to(i)

不过,你不需要改动你的代码,因为for循环会自动调用迭代器的next()方法(以及监视StopIteration异常)。

字典

字典的迭代器会遍历它的键(key)。语句for eachKey in myDict.keys()可以缩写为for eachKey in myDict。另外,Python还引进了三个新的内建字典方法来定义迭代:myDict.iterkeys()(通过键迭代)、myDict.itervalues()(通过值迭代)及myDict.iteritems()(通过键-值对来迭代)。

文件

文件对象生成的迭代器会自动调用readline()方法。这样,循环就可以访问文本文件的所有行。程序员可以使用更简单的for eachLine in myFile替换for eachLine in myFile.readlines()。

如何创建迭代器

对一个对象调用iter()就可以得到它的迭代器,它的语法如下:

iter(object)
iter(func, sentinel)

如果你传递一个参数给iter(),它会检查你传递的是不是一个序列,如果是,那么很简单,根据索引从0一直迭代到序列结束。另一个创建迭代器的方法是使用类,一个实现了iter()和next()方法的类可以作为迭代器使用。
如果是传递两个参数给iter(),它会重复地调用func,直到迭代器的下个值等于sentinel。

列表解析

列表解析(List comprehensions, 或缩略为list comps)来自函数式编程语言Haskell,它可以用来动态地创建列表。列表解析的语法如下:

[expr for iter_var in iterable]

这个语句的核心是for循环,它迭代iterable对象的所有条目。前边的expr应用于序列的每个成员,最后的结果值是该表达式产生的列表。迭代变量并不需要是表达式的一部分。

map(lambda x: x ** 2, range(6))
[0, 1, 4, 9, 16, 25]
[x ** 2 for x in range(6)]
[0, 1, 4, 9, 16, 25]

在新语句中,只用一次函数调用(range()),而之前的语句中有三次函数调用(range()、map()和lambda)。你也可以用括号包住表达式,像[(x**2) for x in range(6)]这样,更便于阅读。结合if语句,列表解析还提供了一个扩展版本的语法:

[expr for iter_var in iterable if cond_expr ]

这个语法在迭代时会过滤或“捕获”满足条件表达式cond_expr的序列成员。

seq = [11, 10, 9, 9, 10, 10, 9, 8, 23, 9, 7, 18, 12, 11, 12]
filter(lambda x: x % 2, seq)
[11, 9, 9, 9, 23, 9, 7, 11]
[x for x in seq if x % 2]
[11, 9, 9, 9, 23, 9, 7, 11]

列表解析支持多重嵌套for循环以及多个if子句。

[(x+1, y+1) for x in range(3) for y in range(5)]
[(1, 1), (1, 2), ... , (3, 5)]

f = open('hhga.txt', 'r')
len([word for line in f for word in line.split()])

列表解析中多重嵌套for循环的for的顺序和普通的写法一致!

生成器表达式

生成器表达式是列表解析的一个扩展。生成器是特定的函数,允许你返回一个值,然后“暂停”代码的执行,稍后恢复。列表解析的一个不足就是必须生成所有的数据,用以创建整个列表。这可能对有大量数据的迭代器有负面效应。生成器表达式通过结合列表解析和生成器解决了这个问题。
生成器表达式与列表解析非常相似,而且它们的基本语法基本相同;不过它并不真正创建数字列表,而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生”(yield)出来。生成器表达式使用了“延迟计算”(lazy evaluation),所以它在使用内存上更有效。

列表解析:
[expr for iter_var in iterable if cond_expr]
生成器表达式:
(expr for iter_var in iterable if cond_expr)

生成器并不会让列表解析废弃,它只是一个内存使用更友好的结构,基于此,有很多使用生 成器地方。

sum([len(word) for line in f for word in line.split()])
sum(len(word) for line in f for word in line.split())

sum()函数的参数不仅可以是列表,还可以是可迭代对象,比如生成器 表达式)。