全网目前最全python例子(附源码)六、Python利器

Python利器

Python中的三大利器包括:迭代器,生成器,装饰器,利用好它们才能开发出最高性能的Python程序,涉及到的内置模块 itertools提供迭代器相关的操作。此部分收录有意思的例子共计14例。

1 寻找第n次出现位置

def search_n(s, c, n):

    size = 0

    for i, x in enumerate(s):

        if x == c:

            size += 1

        if size == n:

            return i

    return -1

 

 

 

print(search_n("fdasadfadf", "a", 3))# 结果为7,正确

print(search_n("fdasadfadf", "a", 30))# 结果为-1,正确

2 斐波那契数列前n项

def fibonacci(n):

    a, b = 1, 1

    for _ in range(n):

        yield a

        a, b = b, a + b

 

 

list(fibonacci(5))  # [1, 1, 2, 3, 5]

3 找出所有重复元素

from collections import Counter

 

def find_all_duplicates(lst):

    c = Counter(lst)

    return list(filter(lambda k: c[k] > 1, c))

 

 

find_all_duplicates([1, 2, 2, 3, 3, 3])  # [2,3]

4 联合统计次数

Counter对象间可以做数学运算

from collections import Counter

a = ['apple', 'orange', 'computer', 'orange']

b = ['computer', 'orange']

 

ca = Counter(a)

cb = Counter(b)#Counter对象间可以做数学运算

ca + cb  # Counter({'orange': 3, 'computer': 2, 'apple': 1})

 

# 进一步抽象,实现多个列表内元素的个数统计

 

def sumc(*c):

    if (len(c) < 1):

        return

    mapc = map(Counter, c)

    s = Counter([])

    for ic in mapc: # ic 是一个Counter对象

        s += ic

    return s

 

#Counter({'orange': 3, 'computer': 3, 'apple': 1, 'abc': 1, 'face': 1})

sumc(a, b, ['abc'], ['face', 'computer'])

 

5 groupby单字段分组

天气记录:

a = [{'date': '2019-12-15', 'weather': 'cloud'},

 {'date': '2019-12-13', 'weather': 'sunny'},

 {'date': '2019-12-14', 'weather': 'cloud'}]

按照天气字段weather分组汇总:

from itertools import groupbyfor k, items in  groupby(a,key=lambda x:x['weather']):

     print(k)

输出结果看出,分组失败!原因:分组前必须按照分组字段排序,这个很坑~

cloud

sunny

cloud

修改代码:

a.sort(key=lambda x: x['weather'])for k, items in  groupby(a,key=lambda x:x['weather']):

     print(k)

     for i in items:

         print(i)

输出结果:

cloud

{'date': '2019-12-15', 'weather': 'cloud'}

{'date': '2019-12-14', 'weather': 'cloud'}

sunny

{'date': '2019-12-13', 'weather': 'sunny'}

6 itemgetter和key函数

注意到sort和groupby所用的key函数,除了lambda写法外,还有一种简写,就是使用itemgetter:

a = [{'date': '2019-12-15', 'weather': 'cloud'},

 {'date': '2019-12-13', 'weather': 'sunny'},

 {'date': '2019-12-14', 'weather': 'cloud'}]from operator import itemgetterfrom itertools import groupby

 

a.sort(key=itemgetter('weather'))for k, items in groupby(a, key=itemgetter('weather')):

     print(k)

     for i in items:

         print(i)

结果:

cloud

{'date': '2019-12-15', 'weather': 'cloud'}

{'date': '2019-12-14', 'weather': 'cloud'}

sunny

{'date': '2019-12-13', 'weather': 'sunny'}

7 groupby多字段分组

itemgetter是一个类,itemgetter('weather')返回一个可调用的对象,它的参数可有多个:

from operator import itemgetterfrom itertools import groupby

 

a.sort(key=itemgetter('weather', 'date'))for k, items in groupby(a, key=itemgetter('weather')):

     print(k)

     for i in items:

         print(i)

结果如下,使用weather和date两个字段排序a,

cloud

{'date': '2019-12-14', 'weather': 'cloud'}

{'date': '2019-12-15', 'weather': 'cloud'}

sunny

{'date': '2019-12-13', 'weather': 'sunny'}

注意这个结果与上面结果有些微妙不同,这个更多是我们想看到和使用更多的。

8 sum函数计算和聚合同时做

Python中的聚合类函数sum,min,max第一个参数是iterable类型,一般使用方法如下:

a = [4,2,5,1]

sum([i+1 for i in a]) # 16

使用列表生成式[i+1 for i in a]创建一个长度与a一行的临时列表,这步完成后,再做sum聚合。

试想如果你的数组a长度十百万级,再创建一个这样的临时列表就很不划算,最好是一边算一边聚合,稍改动为如下:

a = [4,2,5,1]

sum(i+1 for i in a) # 16

此时i+1 for i in a是(i+1 for i in a)的简写,得到一个生成器(generator)对象,如下所示:

In [8]:(i+1 for i in a)

OUT [8]:<generator object <genexpr> at 0x000002AC7FFA8CF0>

生成器每迭代一步吐出(yield)一个元素并计算和聚合后,进入下一次迭代,直到终点。

9 list分组(生成器版)

from math import ceil

def divide_iter(lst, n):

    if n <= 0:

        yield lst

        return

    i, div = 0, ceil(len(lst) / n)

    while i < n:

        yield lst[i * div: (i + 1) * div]

        i += 1

 

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

list(divide_iter([1, 2, 3, 4, 5], 2))  # [[1, 2, 3], [4, 5]]

10 列表全展开(生成器版)

#多层列表展开成单层列表

a=[1,2,[3,4,[5,6],7],8,["python",6],9]def function(lst):

    for i in lst:

        if type(i)==list:

            yield from function(i)

        else:

            yield i

print(list(function(a))) # [1, 2, 3, 4, 5, 6, 7, 8, 'python', 6, 9]

11 测试函数运行时间的装饰器

#测试函数执行时间的装饰器示例import timedef timing_func(fn):

    def wrapper():

        start=time.time()

        fn()   #执行传入的fn参数

        stop=time.time()

        return (stop-start)

    return wrapper@timing_funcdef test_list_append():

    lst=[]

    for i in range(0,100000):

        lst.append(i)  @timing_funcdef test_list_compre():

    [i for i in range(0,100000)]  #列表生成式

a=test_list_append()

c=test_list_compre()

print("test list append time:",a)

print("test list comprehension time:",c)

print("append/compre:",round(a/c,3))

 

test list append time: 0.0219423770904541

test list comprehension time: 0.007980823516845703

append/compre: 2.749

12 统计异常出现次数和时间的装饰器

写一个装饰器,统计某个异常重复出现指定次数时,经历的时长。

import timeimport math

 

def excepter(f):

    i = 0

    t1 = time.time()

    def wrapper(): 

        try:

            f()

        except Exception as e:

            nonlocal i

            i += 1

            print(f'{e.args[0]}: {i}')

            t2 = time.time()

            if i == n:

                print(f'spending time:{round(t2-t1,2)}')

    return wrapper

 

关键词nonlocal常用于函数嵌套中,声明变量i为非局部变量;

如果不声明,i+=1表明i为函数wrapper内的局部变量,因为在i+=1引用(reference)时,i未被声明,所以会报unreferenced variable的错误。

使用创建的装饰函数excepter, n是异常出现的次数。

共测试了两类常见的异常:被零除和数组越界。

n = 10 # except count

@excepterdef divide_zero_except():

    time.sleep(0.1)

    j = 1/(40-20*2)

# test zero divived exceptfor _ in range(n):

    divide_zero_except()

 

@excepterdef outof_range_except():

    a = [1,3,5]

    time.sleep(0.1)

    print(a[3])# test out of range exceptfor _ in range(n):

    outof_range_except()

 

打印出来的结果如下:

division by zero: 1

division by zero: 2

division by zero: 3

division by zero: 4

division by zero: 5

division by zero: 6

division by zero: 7

division by zero: 8

division by zero: 9

division by zero: 10

spending time:1.01

list index out of range: 1

list index out of range: 2

list index out of range: 3

list index out of range: 4

list index out of range: 5

list index out of range: 6

list index out of range: 7

list index out of range: 8

list index out of range: 9

list index out of range: 10

spending time:1.01

13 定制递减迭代器

#编写一个迭代器,通过循环语句,实现对某个正整数的依次递减1,直到0.class Descend(Iterator):

    def __init__(self,N):

        self.N=N

        self.a=0

    def __iter__(self):

        return self

    def __next__(self):

        while self.a<self.N:

            self.N-=1

            return self.N

        raise StopIteration

    

descend_iter=Descend(10)

print(list(descend_iter))

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

核心要点:

1 __nex__名字不能变,实现定制的迭代逻辑

2 raise StopIteration:通过 raise 中断程序,必须这样写

14 测试运行时长的装饰器

#测试函数执行时间的装饰器示例import timedef timing(fn):

    def wrapper():

        start=time.time()

        fn()   #执行传入的fn参数

        stop=time.time()

        return (stop-start)

    return wrapper

@timingdef test_list_append():

    lst=[]

    for i in range(0,100000):

        lst.append(i)  

@timingdef test_list_compre():

    [i for i in range(0,100000)]  #列表生成式

 

a=test_list_append()

c=test_list_compre()

print("test list append time:",a)

print("test list comprehension time:",c)

print("append/compre:",round(a/c,3))

# test list append time: 0.0219# test list comprehension time: 0.00798# append/compre: 2.749

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值