用pythonic方式来思考(3)

2018-05-01  本文已影响0人  小懒额
第10条:尽量用 enumerate 取代 range

内置 range 函数可以完成整数上的迭代,如:

for i in range(5):
    print(i)
>>>
0
1
2
3
4

然而对列表进行迭代时,还想知道索引的时候,如果用 range 函数,只能勉强这样:

list = [1, 2, 3, 4, 5]
for i in range(len(list)):
    print(i, list[i])
>>>
0 1
1 2
2 3
3 4
4 5

python 提供了内置的 enumerate 函数,可以优雅的处理这种问题,

list = [1, 2, 3, 4, 5]
for index, value in enumerate(list):  # enumerate 把迭代器包装为生成器
    print(index, list[index])
>>>
0 1
1 2
2 3
3 4
4 5
第11条:用 zip 函数同时遍历两个迭代器

在同时遍历两个列表,而且两个列表之间存在关联的时候,就可以使用 zip 来进行迭代。zip 能够将两个和两个以上的迭代器中的值封装成生成器。

name_list = ['xiaoli', 'xiaowu', 'xiaolan', 'xiaonwang']
len_name = [len(n) for n in name_list]

max_len = 0
for name, len_name in zip(name_list, len_name):
    if len_name > max_len:
        max_len = len_name
        longest_name = name
print(longest_name, max_len)
>>>
xiaonwang 9

在 Python2 中zip不是生成器,而是迭代器产生的值的元组构成的列表,会占用大量内存。应该使用 itertools 中的 izip 函数。
zip 函数遍历到任何一个迭代器结束时,就停止,所以如果有多个长度不同的迭代器时,在迭代次数最少的迭代器结束时就停止遍历其他的迭代器了。

第12条:不要在 for 和 while 循环后面写 else 块

Python 支持在循环内部的语句块后直接编写 else 块。

for i in range(3):
    print('Loop %d' % i)
else:
    print('Else block!')
>>>
Loop 0
Loop 1
Loop 2
Else block!

从上面运行实例可以看出,else 块在循环结束后直接执行。

for i in range(3):
    print('Loop %d' % i)
    if i == 1:
        break
else:
    print('Else block!')
>>>
Loop 0
Loop 1
Loop 2

这时我们在 循环语句中加上 break 提前结束循环,这时就没有执行 else 块。while 语句也是如此,

i = 0
while True:
    i += 1
    print('Loop %d' % i)
    if i > 3:
        break
else:
    print('Else block!')
>>>
Loop 0
Loop 1
Loop 2
Loop 3

所以, 循环后面的 else 只会在循环完全结束时才会执行,提前 break 出来时不会执行的。

第13条:合理利用 try/except/else/finally 结构中的每个代码块

Python 程序的异常处理可能要考虑四种不同的时机,这些时机可以用 try、except、else 和 finally 来表述。

1.finally 块

既要将异常向上传播,又要在异常发生时执行清理工作,就可以使用 try/finally 结构。这种结构可以用来确保程序能够可靠地关闭文件句柄。

handle = open('/tmp/random_data.txt')  #open 放在 try 外面,否则open时IOError异常不会进入finally
try:
    data = handle.read()
finally:
    handle.close()
2.else块

在 try/else模块中,如果 try 块没有异常,就会执行 else 块。有了这个,就应该缩减 try 内的代码量,使其更加易读。
例如在字符串中加载 json 字典数据,返回字典里某个键所对应的值:

def load_json_key(data, key):
    try:
        result_dict = json.loads(data)
    except ValueError as e:
        raise  KeyError from e
    else:
        return result_dict[key]

这种写法使异常行为更加清晰。

3.混合使用

如果在复合语句中把上面几种机制都用到的话,可以使代码更简洁易懂。
比如在读取文件内容并对读取内容进行处理时,可以这样:

def devide_json(path):
    handle = open(path, 'r+')
    try:
        data = handle.read()
        op = json.loads(data)
        value = (
            op['numerator']/
            op['denominator']
        )
    except ZeroDivisionError as e:
        return UNIDEFINED
    else:
        op['result'] = value
        result = json.dumps(op)
        handle.seek(0)
        handle.write(result)
        return value
    finally:
        handle.close()
上一篇下一篇

猜你喜欢

热点阅读