美文网首页
Python笔记 (二) 进阶

Python笔记 (二) 进阶

作者: 今夕何夕_walker | 来源:发表于2017-03-02 23:21 被阅读14次

    进阶语法

    with ... as 上下文管理协议

    with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。

    已经加入对上下文管理协议支持的还有模块 threading、decimal 等。

    # 操作文件
    with open('file.txt') as f:
        for line in f:
            print(line)
    

    匿名函数lambda

    在python中使用lambda来创建匿名函数,在需要传递函数作为参数的地方使用lambda更方便。

    一个lambda的例子

    list(map(lambda x: x*x, [1,2,3,4,5]))  #[1, 4, 9, 16, 25]
    
    # lambdx x: x*x 等于下面的f函数  可以直接f = lambda x: x*x 赋值后调用
    def f(x):
        return x*x
    list(map(f,[1,2,3,4,5]))
    
    

    对象模拟函数 可调用接口

    对象通过__call__(self [, *args [, **kwargs]])方法模拟函数行为。如果一个对象x提供了该方法,就可以像函数一样调用它。

    class DistanceFrom(object):
        def __init__(self,origin):
            self.origin = origin
        def __call__(self,x):
            return abs(x-self.origin)
            
    nums = [1,37,42,101,13,9,-20]
    newnums = sorted(nums,key=DistanceFrom(10))  #按照与10的距离排序
    

    以上效果等同于

    newnums = sorted(nums,lambda x:abs(x-10))
    

    当然也可以直接把DistanceFrom定义成函数

    使用闭包

    将组成函数的语句和这些语句的执行环境打包在一起时,得到的对象称为闭包

    # 计数器测试闭包效率,和使用类的时候对比
    import timeit
    def count(x):
        def next():
            nonlocal x
            n = x
            x -= 1
            return n
        return next
    
    class count2:
        def __init__(self,x):
            self.x = x
        def next(self):
            n = self.x
            self.x -= 1
            return n
        
    def test():
        next = count(1000000)
        while 1:
            v = next()
            if not v:break
    
    def test2():
        c = count2(1000000)
        while 1:
            v = c.next()
            if not v:break
            
    t2 = timeit.timeit(test2,number=10)
    print(t2)
    t = timeit.timeit(test,number=10)
    print(t)
    
    # 输出结果,闭包效率大概是正常方法的2倍
    # 4.5261534636385345
    # 2.468003824508422
    

    装饰器

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

    参考知乎:如何理解Python装饰器?

    @wraps(func)装饰装饰函数,能把原函数的元信息拷贝到装饰器函数中。

    上面闭包性能测试改成使用装饰器测试性能

    import timeit
    
    def timeit_test(number):
        def decorated(func):
            print(timeit.timeit(func,number=number))
            return func
        return decorated
    
        '''略'''
        '''略'''
    
    @timeit_test(number=10)
    def test():
        next = count(1000000)
        while 1:
            v = next()
            if not v:break
            
    @timeit_test(number=10)
    def test2():
        c = count2(1000000)
        while 1:
            v = c.next()
            if not v:break
    # 装饰器中已运行测试方法,不需要再主动运行
    

    yield和生成器

    尽量使用生成器
    range(num) ----> xrange(nums) #仅限python2,python3中range就等于之前的xrange
    for k,v in dict.items() ----> for k,v in dict.iteritems()
    for k in dict.keys() ----> for k in iterkeys()

    yied生成斐波那契数列

    def fab(max):
        n ,a, b = 0, 0 ,1
        while n < max:
            print('before fab %d' %n)
            yield a
            print('after fab %d' %n)
            a, b = b, a + b
            n += 1
    
    for n in fab(5):
        print(n)
    # 迭代就是重复运行__next__()
    print('//////////////////////////////////////////')
    c = fab(5)
    print(c.__next__())
    print(c.__next__())
    print(c.__next__())
    print(c.__next__())
    print(c.__next__())
    

    for循环迭代fab(5)等同于

    c = fab(5)
    print(c.__next__())   #运行5次
    

    注意运行结果,每循环一次其实代码只执行到yield那一行,下一次循环直接从yield后面的代码开始执行到下一次调用yield

    Paste_Image.png

    yield和协程

    def fab():
        a, b, n = 0, 1 ,0
        fablist = []
        while True:
            number = yield fablist  # 返回值不是必须的,如果number = yield,则返回的是None
            while n < number:
                n += 1
                fablist.append(a)
                a, b = b ,a + b
    
    c = fab()
    c.__next__()
    for i in range(3,7):
        print(c.send(i*10))
    

    next()的初始调用是必须的,yield语句那里协程会挂起,等待相关生成器对象c的send()方法给它发送一个值。
    可以定义一个coroutine装饰器改写上述语句,这看起来和tornado以及asyncio很相似了。

    def coroutine(func):
        def start(*args, **kwargs):
            c = func(*args, **kwargs)
            c.__next__()
            return c
        return start
    
    
    @coroutine
    def fab():
        a, b, n = 0, 1 ,0
        fablist = []
        while True:
            number = yield fablist
            while n < number:
                n += 1
                fablist.append(a)
                a, b = b ,a + b
    
    c = fab()
    #c.__next__()  #加上自定义的coroutine装饰器之后,不需要这个初始调用了
    for i in range(3,7):
        print(c.send(i*10))
    

    continue....

    相关文章

      网友评论

          本文标题:Python笔记 (二) 进阶

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