zoukankan      html  css  js  c++  java
  • 疫情环境下的网络学习笔记 python 3.25

    3.25

    上节课回顾

    1. 有参装饰器

      def deco(x,y)
          def outer(func):
              wrapper(*args,**kwargs):
                  res = func(*args,**kwargs)
                  return res
              return wrapper
          return outer
      
      @deco(1,2)
      def index()
      
    2. 让函数名,文档注释也一模一样

      from functiontools import wraps

      @wraps(func)

    3. 可迭代对象:iter()

      迭代器对象:next()

      迭代器结束异常:stopiteration

    4. for循环工作原理

      1. iter()转换成迭代器对象
      2. next(迭代器对象) 得到一个新的值
    5. 惰性计算:只有执行next(),才会往下取一个值,节省内存

    6. 生成器:函数中用yield

      本身不是函数,调用得到的结果与函数体代码无关,得到的结果是一个自定义的迭代器

      def func():
      	print('1')
      	yield 1
      	print('2')
      	yield 2	
      

      yield可以将函数挂起,暂停函数

      return只能返回一次值,函数就结束了,yield可以返回多次值

    今日内容

    1. 叠加多个装饰器的加载,运行分析

    2. 生成器的高级玩法:yield 挂起函数

      x = yield 返回值,可以赋值

    3. 三元表达式

    4. 生成式

    5. 函数的递归调用

    6. 二分法

    正课

    叠加多个装饰器

    下面例子,叠加3个装饰器

    def deco1(x,y)
        def outer1(func1):  # 拿到wrapper2的内存地址进行装饰,返回wrapper1
            def wrapper1(*args,**kwargs):
                res1 = func(*args,**kwargs)
                return res1
            return wrapper1
        return outer1
    
    def deco2(x,y)
        def outer2(func2):  # 拿到的是wrapper3的内存地址进行装饰,返回wrapper2
            def wrapper2(*args,**kwargs):
                res2 = func(*args,**kwargs)
                return res2
            return wrapper2
        return outer2
    
    
    def deco3(x,y)
        def outer3(func3):  #拿到原函数index的内存地址,返回wrapper3
            def wrapper3(*args,**kwargs):
                res3 = func(*args,**kwargs)
                return res3
            return wrapper3  # 得到wrapper3的内存地址
        return outer3
    
    
    @deco1(1,2)  # deco1(wrapper2)==>index=wrapper1的内存地址
    @deco2(1,2)  # deco2(wrapper3)==>index=wrapper2的内存地址
    @deco3(1,2) #==>outer3==>index=outer3(index)==>index=wrapper3的内存地址
    def index():
        ...
        
    # 最终返回wrapper1的内存地址
    

    在没有调用函数,定义函数的阶段:多个装饰器叠加,加载顺序自下而上

    多个装饰器执行顺序

    def outter1(func1): #func1=wrapper2的内存地址
        ...
        return wrapper1
    
    def outter2(func2): #func2=wrapper3的内存地址
        ...
        return wrapper2
    
    def outter3(func3): # func3=最原始的那个index的内存地址
        ...
        return wrapper3
    
    
    
    @outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
    @outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址
    @outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址
    def index():  # 定义阶段自下而上
        print('from index')
        
    index()  # 调用阶段自上而下
    

    调用函数的阶段:执行顺序:自上而下

    yield表达式

    g.send( )

    除了 next 以外,生成器还有别的用法

    def dog(name):
        print('ready to go')
        while True:
            x = yield  # x会拿到yiled通过 g.send() 接收到的值
            print(name,'x received:', x)
    
    
    g = dog('aaa')  # 此时不会执行,而是返回一个生成器,赋值给g
    next(g)  # 第一次执行dog(),运行到第一个 yield,挂起函数并返回
    g.send('send1')  # 使用send方法向dog()中的 yield 赋值'send1',yield赋值给x后,继续往下运行,经过一个while循环又遇到了yield,挂起并返回
    g.send('send2')  # 向yield赋值'send2',开始执行代码:将yield赋值给x后继续往下执行,遇到下一个yield返回
    
    # ready to go
    # aaa x received: send1
    # aaa x received: send2
    

    只要函数内出现yield,再调函数就跟原代码没关系了,就会返回一个生成器

    g.send(item) 可以给yield赋值,yiled会将得到的值拿给x,相当于在next的基础之上加了一个给yield传值的功能

    原来的函数使用方法,函数的执行顺序一溜烟到底,名称空间就被销毁了。使用yield则不会销毁,而是在第一次g.send(None) 后挂起,等待后续传值

    其他注意的知识点:

    next(g)  # 要使用g.send,必须先send None一次或着next一次,让函数在这里挂起,等待传值
    g.send('send1')
    g.send('send2')
    g.close()  # 可以关闭生成器,关闭之后不能再send值进去,再传就报错
    

    返回值

    def dog(name):
        lis=[]
        print('ready to go')
        while True:
            x = yield lis # x会拿到yiled通过 g.send() 接收到的值
            print(name,'x received:', x)
            lis.append(x)
    
    res = g.send(None)
    print(res)
    
    #send给yield传值, 先赋值给左边的x, 执行下面的代码, 到while循环的下一次, 又遇见yield, 这个时候就返回右边的那个返回值
    

    send(),yield() 的赋值与返回 的执行顺序

    1. 先g.send() 赋值给左边的x
    2. 执行下面的代码, 到while循环的下一次, 又遇见yield
    3. 这个时候就返回yield 右边的那个返回值

    三元表达式

    现有一需求:条件成立,返回一个值,条件不成立,返回另一个值

    对这个需求可以写一个函数,if判断,return不同的值

    def func(x,y):
    	if x > y:
    		return x
    	else:
    		reyurn y
            
    res = func(1,2)
    

    使用三元表达式,用一行代码解决上面这个函数的功能

    x = 1
    y = 2
    
    res = x if x > y else y
    # x>y 不成立,返回else 右边的值
    
    
    # 条件成立时要返回的值 if 条件 else 条件不成立时要返回的值
    

    条件成立时要返回的值 if 条件 else 条件不成立时要返回的值

    生成式

    列表生成式

    把生成列表的代码,改一改放到中括号内

    l = ['aaaa','aacca','dddaa','eeeaa']
    
    new_l = [name for name in l if name.endswith('a')]
    # for循环每循环一次,做一个条件判断,符合判断的加进列表里
    # 相当于
    for name in l:
        if name.endswith('a'):
    		new_l.append(name)
    

    也可以不加条件,相当于 if True

    new_l = [name for name in l]
    
    print(new_l)  # 就是循环原列表一个个加入新列表
    

    课堂小练习:把所有小写字母变成大写,去掉元素的后缀aaa

    lis = ['deimsaaa','zjyaaa','bbbaaa','cccaaa','sss']
    new_lis = [name[:-3].upper() for name in lis if name.endswith('aaa')]
    print(new_lis)
    

    字典生成式

    keys = ['name','age','gender']
    {key:None for key in keys}
    # 生成字典,为所有的key赋值None
    
    
    items = [('name','deimos'),('age','21'),('gender','mail')]
    {for k,v in items if k != 'gender'}
    # 循环 items,第一个为key,第二个为值加入字典,判断 k = gender的时候不加入字典
    

    集合生成式

    keys = ['name','age','gender']
    set1 = {key for key in keys}
    print(set1,type(set1))
    

    生成器生成式

    除了用yield + 函数定义之外,另一种创建生成器的方法。与列表生成式的语法格式相同,只需要将 []换成 (),返回的不是列表或元组,返回的是一个生成器对象

    例子:统计文件中所有字符的个数

    • sum( iteration ):里面放一个可迭代对象,会迭代之后累加

      sum的原理也是for 循环,然后next取值进行累加计算

    • 生成器生成式:(expression for item in iterable if condition)

    方法一,最原始的方法 用for循环

    with open('笔记.txt',mode='rt',encoding='utf-8') as f:
        # 方式一:
        res=0
        for line in f:
            res+=len(line)
        print(res)
    

    方法二:使用列表生成器,对每一行计算长度 len(line)加入列表,最后求sum

    res=sum([len(line) for line in f])
        print(res)
    # 可以实现,但是当文件有很多行,列表生成器生成的每一个元素都在内存中占地方,sum的运行效率会很低
    

    方法三:使用生成器表达式

    res = sum(len(line) for line in f)
        print(res)
    # 在类似sum() 这样的函数中写生成器表达式不需要加括号,sum() 能够识别
    

    函数递归调用

    递归:我 调 我 自 己

    def f():
    	print('f1')
    	f()
    
    f()
    # 直接调用本身
    

    递归像死循环,永远不会结束第一层函数名称空间,python不允许无限地递归,默认设置了最大层级:1000层

    def f():
    	print('f')
    	f1()
    	
    def f1()
    	print('f1')
    	f()
    f()
    # 间接调用,仍然是死循环
    

    递归的本质就是循环,一段代码的循环运行方案有两种:循环,递归,就是用于重复运行代码的

    递归无限运行,会无限申请内存空间,python也没有尾递归或别的方法优化,所以不应该无限地递归,必须在满足某种条件下结束递归调用:return

    def f(n):
        if n == 15:  # 判断条件,满足时return退出,不会造成无限递归
            return 
        print(n)
        n += 1
        f(n)
    
    f(1)
    

    递归的两个阶段

    • 回溯:一层层往下调用函数的过程
    • 递推:运行结束后一层一层结束函数

    函数递归的过程:

    回溯====》到达最下一层函数,返回====》一层层递推回来
    

    例子:对一个嵌套了很多层的列表,将列表里列表里列表里所有的元素取出来

    items=[[1,2],3,[4,[5,[6,7]]]]
    def foo(items):
        for i in items:
            if isinstance(i,list): #满足未遍历完items以及if判断成立的条件时,一直进行递归调用
                foo(i)
            else:
                print(i,end=' ')
    
    foo(items)
    
  • 相关阅读:
    Set / Map 集合 -ES6
    getter/setter
    构造函数-class类 -语法糖 -ES6
    原型链-继承
    创建对象/克隆
    Generator生成器函数- ES6
    iframe跨域访问
    setTimeout延迟加载
    adt新建项目后去掉appcompat_v7的解决方法
    PHP数组的操作
  • 原文地址:https://www.cnblogs.com/telecasterfanclub/p/12567280.html
Copyright © 2011-2022 走看看