美文网首页
用pythonic方式来思考(2)

用pythonic方式来思考(2)

作者: 小懒额 | 来源:发表于2018-04-28 08:06 被阅读0次
    第5条 了解切割序列的方法

    python 支持对序列进行切片操作,可以对内置的 list、str和bytes 进行切割,切割操作还延伸到实现了 __get_item____set_item__ 的 python 类上。
    基本操作方法: somelist[start:end],切片时包括 start,不包括 end。
    几种切片实例:

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    print(test[0:])
    print(test[:len(test)])
    print(test[:])
    print(test[3:])
    print(test[4:5])
    print(test[-1:])
    print(test[-4:-7])
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8]
    [1, 2, 3, 4, 5, 6, 7, 8]
    [1, 2, 3, 4, 5, 6, 7, 8]
    [4, 5, 6, 7, 8]
    [5]
    [8]
    []
    

    切片时,下标可以越界,但是访问列表下标对应的元素时,不能越界,否则报 IndexError。

    print(test[:20])
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8]
    

    somelist[-0:] 为原列表的拷贝。

    print(test[-0:])
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8]
    

    对原列表进行切割,产生的时一张新列表,在新列表上操作。不会修改原列表。

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    test1 = (test[:])
    test1[2] = 9
    print(test1)
    print(test)
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8]
    [1, 2, 9, 4, 5, 6, 7, 8]
    

    在对列表进行切割时赋值,列表会根据新值的个数相应扩张或收缩。

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    test[:2] = [9, 9, 9, 9]
    print(test)
    test[:5] = [1,2]
    print(test)
    >>>
    [9, 9, 9, 9, 3, 4, 5, 6, 7, 8]
    [1, 2, 4, 5, 6, 7, 8]
    
    第6条:在单次切片操作时,不要同时指定 start、end 和 stride

    列表的步进切割,

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    print(test[::2])
    >>>
    [1, 3, 5, 7]
    

    当步进值为 -1 时,可以实现序列的翻转效果,(书上说这里不能够对 utf8 的unicode实现翻转,测试了下好像可以实现)

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    print(test[::-1])
    >>>
    [8, 7, 6, 5, 4, 3, 2, 1]
    
    a = 'hello world'
    print(a[::-1])
    >>>
    dlrow olleh
    
    a = '你好'
    print(a[::-1])
    b = u'你好'
    print(b[::-1])
    c = a.encode('utf-8')
    print(c[::-1])
    d = c.decode('utf-8')
    print(d)
    >>>
    好你
    好你
    b'\xbd\xa5\xe5\xa0\xbd\xe4'
    你好
    

    切割列表时,在一堆中括号里写上三个数字太过于拥挤,而且不利于阅读。
    如果对内存要求不是特别严格,尽量在使用时先做步进切割,再做内存切割。

    第7条:用列表推导式来取代 map 和 filter

    如果用下面列表里面的每个元素的平方来构建一个新的列表,先看一下 map 的做法:

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    squa = map(lambda x: x**2, test)
    print list(squa)
    >>>
    [1, 4, 9, 16, 25, 36, 49, 64]
    

    使用列表推导式是这样:

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    squa = [x**2 for x in test]
    print(squa)
    >>>
    [1, 4, 9, 16, 25, 36, 49, 64]
    

    这时如果只对列表中的偶数的平方值构建列表,使用 map 的时候需要配合 filter 才能实现,

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    squa = map(lambda x:x**2, filter(lambda x:x%2 ==0, test))
    print list(squa)
    >>>
    [4, 16, 36, 64]
    

    但是列表推导式来实现就是这样:

    test = [1, 2, 3, 4, 5, 6, 7, 8]
    squa = [x**2 for x in test if x%2 == 0]
    print(squa)
    >>>
    [4, 16, 36, 64]
    

    可以看出,列表推导式的写法和可阅读性都强很多。

    第8条:不要使用含有两个以上的列表推导式

    当使用列表推导的多重循环时,可以实现将二维列表转换成一维列表。如:

    matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    flat = [x for row in matrix for x in row]
    print(flat)
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    然而当使用列表推导的多重循环时,效果如下:

    matrix = [[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]
    flat = [x for row in matrix for line in row for x in line]
    print(flat)
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    这时候看起来没有很简洁,如果换成普通的循环语句,反而更清晰一点,

    flat = []
    matrix = [[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]
    for row in matrix:
        for line in row:
            flat.extend(line)  #这里使用 extend 而不是 append 可以减少一行
    print(flat)
    >>>
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    除了多重循环之外,列表推导式还包括多重条件,

    matrix = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    flat = [x for x in matrix if x%2 == 0 if x >4]
    print(flat)
    >>>
    [6, 8]
    

    实际使用中尽量避免去使用多重循环或者多重条件,最好只使用两个循环,两个条件,或者一个循环一个条件。

    第9条:用生成器表达式来改写数据量较大的列表推导

    在使用列表推导式时,需用使用一块内存来存储生成的全新列表,当数据量比较大时,这消耗大量内存。
    如:

    value = [len(x) for x in open('/tmp/my_file.txt')]
    

    当这个文件非常大时,就会出现内存消耗过多的问题。
    这个时候就需要生成器表达式来解决这个问题。生成器表达式在运行时,不会立刻加载所有数据,而是每次循环时使用迭代器主次返回数据。
    把实现列表推导的写法放在()中,就实现了生成器表达式。
    如:

    value_generator = (len(x) for x in open('/tmp/my_file.txt'))
    print(value_generator )
    >>>
    <generator object <genexpr> at 0x02A5F0C0>
    

    连锁生成器表达式,

    matrix = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    it = (x for x in matrix)  # 这里的it作为生成器继续使用
    print(it)
    roots = ((x, x**5) for x in it)  # it在使用时会记录当前状态,使用后不能继续使用
    print(roots)
    print(next(roots))
    print(next(roots))
    print(next(roots))
    >>>
    (1, 1)
    (2, 32)
    (3, 243)
    

    相关文章

      网友评论

          本文标题:用pythonic方式来思考(2)

          本文链接:https://www.haomeiwen.com/subject/mmaulftx.html