zoukankan      html  css  js  c++  java
  • python入门到放弃-函数专题

    一、函数的定义

    函数是对代码块和功能的封装和定义


    #函数的语法:def是define的意思,定义
    最基本的语法:
        def 函数名():
            函数体
       函数名() #调用函数
    带有参数的语法
    def 函数名(形参列表): 函数体(代码块,return) 函数名(实参列表) :调用

    #例子:函数执行过程
    # def wan():  #定义函数
    #     print("今天一起去玩")
    #     print("去哪里玩呢")
    #     print("我不知道")
    # wan()  #调用函数
    '''讲解执行的过程
        1.定义函数wan()
        2.调用函数wan()
        3.准备开始执行函数
        4.打印,今天一起去玩
        5.打印,去哪里完
        6.打印,我不知道
        7.函数执行完毕,本次调用完毕,wan()函数调用完毕
    '''

    二.return返回值的相关操作

    return:在函数执行的时候,如果遇到return,则直接返回,和while循环中break一样
        1、如果函数什么都不写,不写return,没有返回值,得到的是Nano
        2、在函数中间或者末尾写return,返回的是None
        3、在函数中写 return 值,返回的是一个值
        4、在函数中有返回多个返回值,return 值1、值2、值3... 返回接收到的是元组
    
    #例子:    
    #1、函数什么都不写,不写return,返回的是None
    def wan():
        print("今天一起去玩")
        print("去哪里玩呢")
        print("我不知道")
    ret = wan()
    print(ret)  #None
    
    #2、在函数中间或者末尾写return,返回的是None
    def wan():
        print("今天一起去玩")
        return
        print("去哪里玩呢")
        print("我不知道")
    ret = wan()
    print(ret)  #在执行完第一个print的时候就返回None,就结束了
    
    #3、在函数中写一个return 值,返回的是一个值
    def wan():
        print("今天一起去玩")
        return "锅盖"
        print("去哪里玩呢")
        print("我不知道")
    ret = wan()
    print(ret)
    #今天一起去玩
    #锅盖
    #会看到返回锅盖就结束了
    
    #4、函数中有返回多个返回值,那么返回的是一个元组
    def wan():
        print("今天一起去玩")
        return "锅盖","番薯","大块"
        print("去哪里玩呢")
        print("我不知道")
    ret = wan()
    print(ret)  ##('锅盖', '番薯', '大块')
    相关操作

    三.函数的参数

    函数在调用的时候指定具体的一个变量的值,就是参数

    #参数包括:形参,实参,传参

    形参:函数声明的位置的变量
    实参:函数调用的时候给的具体的值
    传参:把实参交给形参的过程

    #相关参数具体位置例子

    #形参和实参的位置
    # def wan(形参):  #在函数声明的位置的变量就是形参
    #     print(好玩)
    # 
    # wan(实参) :#在函数调用的地方给的具体的值就是实参
    
    #例子
    # def wan(what):
    #     print("手机")
    #     print("去哪里"+what)
    # wan("广西")
    #在调用wan的时候给what一个值,然后执行函数体

    #实参的相关操作

    #包括
        1.位置参数:按照形参的参数位置,给形参传值
        2.关键字参数:按照形参的名字给形参传值
        3.混合参数:即用位置参数,也用关键字参数

    #实参操作的例子:

    # 1、位置参数,按照形参的位置,给形参传值
    #例子
    # def chi(moning,after,night):
    #     print(moning,after,night)
    # chi("玉米饺","米饭","面条") #玉米饺 米饭 面条
    
    
    #2.关键字参数: 按照形参的名字给形参传值
    # def chi(moning,after,night):
    # #     print(moning,after,night)
    # # chi(after="米饭",moning="饺子",night="面条") #饺子 米饭 面条
    
    # 3.混合参数:即用位置参数,也用关键字参数
    # def chi(moning,after,night):
    #     print(moning,after,night)
    # chi("饺子","米饭",night="面条") #饺子 米饭 面条
    
    #注意:
        #顺序位置:要先写位置后再写关键字,要不然会报错
    #例子
    # chi("饺子",night="面条","米饭")  #会报红色
    #SyntaxError: positional argument follows keyword argument
    #语法错误:关键字参数后面跟了位置参数

    #形参的相关操作

    #包括
        1.位置参数
        2.默认值参数,要先写位置参数之后才能写默认值参数
        3.动态参数
         包括:位置参数动态传参 *args,关键字参数动态传参**kwargs
        无敌传参方法:def func(*args,**kwargs):

    #形参操作的例子:

    #1.位置参数,按照位置来进行赋值
    # def chi(moning,after,night):
    #     print(moning)
    #     print(after)
    #     print(night)
    # chi("饺子","米饭","面条")
    
    
    #2.默认值参数
    #例子:比如一个班上要录入学生信息,有大部分都是男生,就可以设置一个默认值是男
    # def stu_inf(name,age,sex='男'):
    #     print("录入学生信息")
    #     print(name,age,sex)
    #     print("录入完毕")
    # stu_inf("蒋小鱼",18)
    # stu_inf("张冲",22)
    # stu_inf("沈搁",22,sex="女") #如果不想使用默认值也可以自己设定
    
    #注意点:
        #必须先声明位置参数,才能声明默认值参数,否则会有问题
    #例子
    # def stu_inf(name,sex='男',age): #很明显这种写法是错误的
    
    
    #3.位置参数的动态传参
    #     * 在这里表示接收位置参数的动态传参,接收到的是元组
    # def chi(*foot):  #参数名是food, * 表示动态传参
    #     print(foot)
    # chi("米饭","面条","饺子")  #('米饭', '面条', '饺子')
    # chi("馒头")
    # chi()
    
    # def chi(name,*food,location="河北"):
    #     print(location)
    #     print(name+"要吃",food)
    # chi("张三","饺子","面条")
    
    #要注意参数的书写顺序
    #顺序: 位置参数 -> 位置参数动态传参 -> 默认值参数
    #错误写法
    # def chi(name,location="河北",*food):
    #     print(location)
    #     print(name+"要吃",food)
    # chi("张三","饺子","面条")   #这样写的话饺子就成了默认值
    # 饺子
    # 张三要吃 ('面条',)
    '''
    
    
    #关键字的动态传参
    '''
    # def chi(**food):
    #     print(food)
    #
    # chi(good_food="大米",no_good_food="面条",dirnk="水")
    #前面得是变量,如果写数字或者字符串这种就会报错,如:"大海" = "虾"
    
    # def chi(*food2,**food):
    #这样是无敌传参
    #     print(food)
    #
    # chi(good_food="大米",no_good_food="面条",dirnk="水")
    
    #提示:
    #   位置参数,*args(位置关键字动态传参) 默认值参数 **kwargs 关键字动态传参
    #   以上参数可以任意搭配使用,但是要注意顺序问题,要不然会有问题
    形参相关操作例子

    #参数的位置顺序排列

    位置参数->位置参数动态传参*args->默认值参数->关键字参数动态传参**kwargs

    四.函数的注释

    在函数里面用三个单引号或三个双引号引起来的就是函数的注释

    #例子:写好注释让别人能看明白,能省去很多事情

    # def chi(food,drink):
    #     """
    #     这里是函数的注释,先写一下当前这个函数是干什么的,不如我这个函数就是一个吃
    #     :param food: 参数food是什么意思
    #     :param drink:  参数drink是什么意思
    #     :return:   返回的是什么东西
    #     """
    #     print(food,drink)
    #     return "good"
    # print(chi.__doc__)   #document 文档
    # print(str.__doc__) #查看字符串的文档注释

    #关于参数的聚合和打散

    #形参:聚合
    # def func(*food):
    #     print(food)
    # lst = ["大麻花","饺子","面条","土豆"]
    # func(lst) #这样调用的话是一个列表在里面的
    
    # # 实参: 打散
    # func(lst[0],lst[1],lst[2],lst[3]) #将上面的大三, 把list,tuple,set,str进行迭代打散
    # func(*lst)  #上面的打散写不方便,写*号更方便简单
    # #但是上面的打散都是一个一个的,那么字典呢?
    
    #字典的打散方式
    #聚合成关键字参数
    # def func(**kwargs):
    #     print(kwargs)
    # dic = {"name":"sir","age":"18"}
    # func(**dic)  #打散成关键字参数
    打散和聚合例子

    五.函数名

    函数名也是一个变量,但是一个特殊的变量,与括号配合可以执行函数的变量

    #函数名的相关操作

    1.函数名可以赋值给其他变量
    2.函数名可以作为参数列表中的元素进行存储,作容器类的元素
    3.函数名可以作为参数传递给函数
    4.函数名可以作为函数的返回值

    #函数名相关操作例子:

    # 1、函数名的内存地址
    # def func():
    #     print("哈哈")
    # print(func)  #因为还没有进行调用
    #结果:<function func at 0x0000025A9344C1E0>
    
    
    # 2.函数名可以赋值给其他变量
    # def func():
    #     print("哈哈")
    #
    # print(func)
    # a = func #把函数当成一个变量赋值给另一个变量
    # a()  #函数调用func()
    #打印哈哈
    
    
    # 3.函数名可以当作容器类的元素
    # def func1():
    #     print("哈哈")
    #
    # def func2():
    #     print("哈哈")
    #
    # def func3():
    #     print("哈哈")
    #
    # lst = [func1,func2,func3]
    # for i in lst:
    #     i()
    
    
    # 4.函数名可以作为参数传递给函数
    # def my():
    #     print("我是my")
    #
    # def proxy(fn):
    #     fn() #执行传递过来的my
    # proxy(my)
    #过程:首先调用proxy函数,将my参数传递给proxy,然后变成proxy(my),然后调用my()
        #接着打印"我是my"
    
    #函数名可以作为参数进行传递(多层嵌套)
    # def func():
    #     print("我是func")
    # def func1():
    #     print("我是func1")
    #
    # def func2(fn):
    #     print("我是func2")
    #     fn()
    # func2(func1)  #结果:我是func2,我是func1
    #解释:首先执行func2函数,然后有个实参传递给形参,打印我是func2,然后执行func1()函数打印我是func1
    
    #例二:
    # def func():
    #     print("我是func")
    # def func1():
    #     print("我是func1")
    #
    # def func2(fn,gn):
    #     print("我是func2")
    #     fn()
    #     gn()
    #     print("hahaha")
    # func2(func1,func)
    # 我是func2
    # 我是func1
    # 我是func
    # hahaha
    #解释:首先执行func2函数,有两个实参传递给形参,打印我是func2,接着执行func1函数打印我是func1,
        #接着执行funch函数打印我是func,在打印hahaha
    
    
    # 5.函数名可以作为函数的返回值
    # def func():
    #     print("我是func")
    #     a = 10 # 变量
    #     def inner():
    #         print("我是inner")
    #     return inner  #得出inner,然后使用inner()调用
    # print(func)
    # ret = func()
    # ret()
    # func()() #先运行func() 然后再返回值上加()
    操作例子

    六.函数的嵌套

    1.主要遇见()就是函数被调用了,如果没有()就不是函数的调用
    2.函数的执行顺序

    #函数嵌套例子

    #例子:
    # def fun():
    #     print(111)
    # def fun1():
    #     print(222)
    #     fun()
    # fun1()
    # print(111)
    #结果是222,111,111
    #解释:定义函数,然后最先调用的是fun1这个函数,所以先的打印fun1中的内容,
        #接着再调用fun()函数,再打印111,接着再打印111
    
    #例二
    # def fun1():
    #     print("蒋小雨")
    #     def fun2():
    #         print("鲁炎")
    #     def fun3():
    #         print("张冲")
    #         def fun4():
    #             print("龙大队")
    #             fun2()
    #         fun4()
    #     fun3()
    # def fun5():
    #     print("二哈")
    #     fun1()
    # fun5()
    #二哈,蒋小雨,张冲,龙大队,鲁炎
    #分析:首先调用fun5,打印二哈,接着调用fun1,打印蒋小雨,然后调用fun3的函数,打印张冲
        #接着执行下面函数体代码块,调用fun4,打印龙大队,接着调用fun2打印鲁炎
    嵌套例子

    七.命名空间

    把存放名字和值的关系的空间叫做命名空间

    #命名空间分类

    1.全局命名空间:在py文件中,函数外声明的变量都属于全局命名空间
    2.局部命名空间:在函数中声明的变量会放在局部命名空i教案
    3.内置命名空间:存放python解释器为我们提供的名字
               如:list,tuple,str,int这些就是内置命名空间

    #取值顺序

    1.局部命名空间
    2.全局命名空间
    3.内置命名空间
    
    #取值顺序例子:
    a = 10 #全局命名空间
    def func():
        a = 20 #局部命名空间
        print(a)
    func() #20 

    八.作用域

    定义:作用域就是作用的范围,按照生效范围分为:全局作用域和局部作用域

    全局作用域:包含内置命名空间和全局命名空间,在整个文件都可以使用
          可以通过globals()函数来查看全局作用域中的内容
    局部作用域:在函数内部可以使用
          可以通过locals()函数来查看局部作用域中的变量和函数信息

    #例子:

    #例子
    # a = 10
    # def func():
    #     a = 40
    #     b = 20
    #     def abc():
    #         print("哈哈")
    #     print(a,b)  #这里使用的是局部作用域
    #     print(globals()) #打印全局作用域中的内容
    #     print(locals())  #打印局部作用域中的内容
    # func()

    #关键字global和nonlocal讲解

    global:更改全局变量中的值
        理解:在局部中定义一个局部变量,然后加了global,就会将全局中定义的变量的值改成局部的那个变量的值
    
    #global的应用
    #例子
    # a = 10
    # def func():
    #     global a
    #     a += 10
    #     print(a)
    # func() #20 ,加了global就可以改变外部的值了,如果不加是不能更改的
    
    #例如:不加global更改全局参数的时候就会报错
    # a = 10
    # def func1():
    #     a += 10
    #     print(a)
    # func1()
    #总结点:全局变量本身就是不安全的,不能随意修改
    
    
    nonlocal:寻找外层函数中离他最近的那个变量
    #例子:
    # a = 10
    # def func1():
    #     a = 20
    #     def func2():
    #         nonlocal a
    #         a = 30
    #         print(a)
    #     func2()
    #     print(a)
    # func1()
    # print(a) #30,30,10
    #nonlocal是更改离他最近的那个变量,所以,将上一个a=20,改为30
    #所以打印是30,30,10,因为nonlocal将20改成了30
    详解

    九.闭包

    定义:在内层函数中访问外层函数的变量
    
    闭包的作用:
        1.可以保护变量不受侵害
        2.可以让一个变量常驻内存

    #例子:

    #作用例子:
    #1、保护变量不受侵害
    #首先举一个全局变量不安全的例子
    # a = 10
    # def outer():
    #     global a
    #     a = 20
    #     print(a)
    #
    # def outer_2():
    #     global a
    #     a = 30
    #     print(a)
    #
    #
    # outer()
    # outer_2()
    #得出结果是20,30
    #解释:首先调用outer()函数更改为20,然后再调用outer_2函数打印30
    #       这样就会出现哪个先调用就执行那个,所以改来改去是很混乱的
    
    # def outer():
    #     a = 10  #这个变量对外界是不开放的
    #     def func():
    #         nonlocal a  #寻找外层函数中离他最近的那个进行修改
    #         a = 20
    #         print(a)
    #     func()
    # outer()
    # 
    # def outer_2(): #这个函数不能对a = 10进行修改
    #     pass
    
    #2、让一个变量常驻内存
    # def outer():
    #     a = 10  #常驻内存,为了inner执行的时候有值,因为你不知什么时候调用
    #     def inner():
    #         print(a)
    #     return inner
    # fn = outer()
    # print("大大大")
    # print("笑笑笑")
    #
    # fn() #相当于inner(),调用inner函数
    
    
    #使用 _closure_ 查看函数是不是闭包
    
    #例子:不是闭包的检测
    # def outer():
    #     def func():
    #         print("我不是闭包")
    #     print(func.__closure__)  #None
    # outer()
    
    #例二:是闭包
    # def outer():
    #     a = 10
    #     def func():
    #         print(a)
    #     print(func.__closure__)
    # outer()  #(<cell at 0x000001B7B3E7D978: int object at 0x00007FF97124B470>,)
    
    #结论:如果打印的是None,不是闭包,如果不是None,就是闭包
    作用例子

    十.迭代器

    #迭代器
    #   可以简单理解为:通用的去遍历某个对象的方式
    
    #有些数据类型是可迭代的,有些是不可迭代的,如果使用不可迭代的来进行循环就会报错
    
    #例子:使用不可迭代对象来进行循环就会报错
    # s = 123
    # for i in s:
    #     print(i)
    #这样打印会报错: TypeError: 'int' object is not iterable:数字不是一个可迭代对象
    
    #那么问题就来了,怎么知道是不是一个可迭代对象呢?
    #可以通过dir查看xx类型的数据可以执行哪些方法
    # print(dir(str))  #__iter__ iterable(可迭代)
    # print(dir(list)) #__iter__
    # print(dir(int))    #如果没有__iter__,说明不是可迭代对象,不是可迭代对象那么相对应的就不能进行循环
    
    #结论:所有的带__iter__是可以使用for循环的,是可迭代对象
    
    #可迭代对象就可以使用__iter__()来获取到迭代器
    #迭代器里面有__next__()
    # s = "我喜欢看火蓝刀锋"
    # it = s.__iter__() #获取迭代器
    # print(dir(it))   #迭代器里有__iter__ 还有__next__

    #迭代器的特点

    1.只能向前取,下一个下一个,不能往回
    2.几乎不占用内存,可以有效节省内存
    3.for循环
    4.惰性机制
    
    #例子:
    1.只能向前拿
    #print(it.__next__()) #我
    # print(it.__next__()) #喜
    # print(it.__next__()) #欢
    # print(it.__next__()) #看
    # print(it.__next__()) #火
    
    2.迭代器模拟for循环
    # lst = ["蒋小雨","张冲","鲁炎","龙大队"]
    # for el in lst: #底层使用的是迭代器
    #     print(el)
    特点

    #判断数据是否可迭代

    #例子:
    # lst = ["张冲","鲁炎","蒋小雨"]
    
    #it = lst.__iter__()
    
    # print("__iter__" in dir(it))  #True
    # print("__next__" in dir(it))  #True
    # print(list(it))
    #通过dir来判断数据是否可迭代的,以及数据是否是迭代器
    #
    # #官方方案
    # from collections.abc import Iterable #可迭代对象
    # from collections.abc import Iterator  #迭代器
    #
    # print(isinstance(lst,Iterable))  #True
    # print(isinstance(lst,Iterator))  #False lst列表本身不是迭代器

    十一.生成器

    1.生成器的本质就是迭代器,和迭代器的特点一样,取值方式和迭代器一样(__next__(),send()
    2.在python种有三种方式来获生成器
        1.通过生成器函数
        2.通过各种推导式来实现生成器
        3.通过数据的转换也可以获取生成器

    生成器函数

    1.函数中如果由yield函数就是生成器函数
    2.生成器函数在执行的时候,默认不会执行函数体,会返回生成器
    3.yield:相当于return可以返回数据,但是yield不会彻底中断函数,会分段执行函数
    
    #例子:不执行函数体,拿到的是生成器
    # def func():
    #     print('哈哈')
    #     yield 1
    #     print('呵呵呵')
    # gen = func() #这样子你就会发现不会执行你的函数,拿到的是生成器,如果是return的话就会执行函数了
    # print(gen.__next__()) #这样子就会执行函数,执行到下一个yield,就是说执行看到yield就结束

    #生成器应用

    #应用场景
    # 比如你喜欢吃鸡蛋,设想你去市场可以一下子就买一万个,这样也是可以,但是有个问题就是鸡蛋久了就会烂,存放是个问题,这样就会很浪费,但是如果你买了个鸡回来,就可以解决掉存放空间问题,想什么时候吃就拿一个
    
    #例子:一下子买一万个浪费
    # def egg():
    #     lst = []
    #     for i in range(10000):
    #         lst.append('鸡蛋'+str(i))
    #         return lst
    # ll = egg() #一下子买10000个就会很占用内存
    
    #例二:买只鸡,生鸡蛋,想吃一个就拿一个
    # def egg():
    #     for i in range(10000):
    #         yield '鸡蛋'+str(i)
    # g = egg() #获取生成器
    # sir = g.__next__()
    # print(sir) #鸡蛋0
    # sir1 = g.__next__()
    # print(sir1) #鸡蛋1
    #这样子就是想吃一个就拿一个
    
    #这样子也验证了生成器的3个特点
    #   1.惰性机制,拿一个才给你取一个
    #   2.省内存
    #   3.只能向前拿
    应用场景

    #send()方法

    send()和__next__()是一样的,可以执行到下一个yield,可以给上一个yield位置传值
    
    #send和__next__()区别:
        1.send和next()都是让生成器走下一次
        2.send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send()

    #使用send给上一个yield传值例子:

    #例子:使用send给上一个yield传值
    def func():
        print("我吃什么啊")
        a = yield "玉米"  #这里的a和后面的yield是没关联的,会把传进来的值交给print执行
        print("a=",a)
        b = yield "饺子"
        print("b=",b)
        c = yield "包子"
        print("c=",c)
        yield "OVER"  #最后收尾的一定是yield,不然会有报错
    
    g = func() #获取生成器,记住有yield的是生成器函数,只会给你获取到生成器,不会执行函数体
    ret1 = g.__next__() #没有上一个yield,所以不能使用send(),开头必须__next__()
    print(ret1)
    ret2 = g.send("大饼")
    print(ret2) #a=大饼
    ret3 = g.send("")
    print(ret3) #b=粥
    ret4 = g.send("冰淇淋")
    print(ret4) #c=冰淇淋
    #解析:执行时候首先我吃什么啊,然后打印玉米,接着ret2使用send上一个yield传值,所以就变成a=大饼,接着打印a=大饼
    #       要注意变量和右边的yield是两段来的,互不相干,接着打印饺子,ret3使用send给上一个yield传值,变成b=粥,接着继续执行
    传值例子

    #生成器可以使用for循环来获取内部的元素

    #为什么生成器可以使用for循环呢,因为生成器实质就是迭代器
    #例子:
    def func():
        print(111)
        yield 222
        print(333)
        yield4444
        print(555)
        yield 666
    for i in func():
        print(i)

    十二.推导式

    1.推导式:就是使用一句话来生成
    2.包括:列表推导式,字典推导式,集合推导式,
    3.注意点:没有元组推导式
    4.3种推导式的语法:
        1.列表推导式:[结果 for循环 条件判断]
        2.字典推导式:{k:v for循环 条件判断}
        3.集合推导式:{k for循环 条件判断}

    #3种推导式的应用

    #1.列表推导式
            语法: [结果 for循环 判断语句]
    
    #例子:首先我们先来一个打印一年级到12年级,我们可能想到的是定义一个空列表,然后把元素追加到列表里面
    # lst = []
    # for i in range(1,13):
    #     lst.append("年级"+str(i))
    # print(lst)
    
    #如果使用推导式的话,那么就是使用一句话来生成一个列表
    # lst = ["年级"+str(i) for i in range(1,13)]
    # print(lst)  #和上面列表追加一样的效果
    
    #例二:使用推导式取1-100的奇数
    # lst = [i for i in range(100) if i%2 == 1]
    # print(lst)
    
    #例三:寻找名字中带有两个e的人的名字
    # names = [['Tom','tomi','findall','Wesley','Steven','Jon'],['Alice','Ana','Jennifer','Eva']]
    #逻辑:首先打开第一层列表,拿到下列表,然后再到小列表里面拿元素,再进行统计判断
    
    #使用推导式写
    # lst = [name for line in names for name in line if name.count('e') ==2]
    # print(lst) #['Wesley', 'Steven', 'Jennifer']
    
    #使用常规算法写
    # lst = []
    # for line in names:
    #     for name in line:
    #         if name.count('e') == 2:
    #             lst.append(name)
    # print(lst) #['Wesley', 'Steven', 'Jennifer']
    
    
    #2.字典推导式
            语法:{key:value for循环 条件判断}
    
    #例子:将列表的元素转换成字典,转换形式:[11,22,33,44] => {0:11,1:22,2:33}
    # lst = [11,22,33,44]
    # dic = {i:lst[i] for i in range(len(lst))}
    # print(dic) #{0: 11, 1: 22, 2: 33, 3: 44}
    
    #例二:将字典的key和value进行调换
    #   思路:首先先拿到key和value,然后在推导式的结果那里掉不同位置就可以了
    # dic = {"zs":"赵四","ln":"刘能","zc":"张冲","ly":"鲁炎"}
    # d = {v:k for k,v in dic.items()}
    # print(d) #{'赵四': 'zs', '刘能': 'ln', '张冲': 'zc', '鲁炎': 'ly'}
    
    
    #3.集合推导式
    #要记住集合的特点:去重,无序,元素必须式可哈希不可变的数据类型
    #例1:使用集合推导式去重复
    # s = {i for i in range(100)}
    # print(s)
    
    #例二:去重复
    # lst= [1,2,3,4,2,1,3,4,6,7]
    # s = {el for el in lst}
    # print(s) #{1, 2, 3, 4, 6, 7}
    推导式应用

     

    十三.生成器表达式

    1.生成器表达式可以直接获取到生成器对象,生成器对象可以直接进行for循环,生成器具有惰性机制
    2.生成器表达式语法:
            (结果 for 变量 in 可迭代对象 if 条件判断)

    #生成器表达式应用

    #下面将演示生成器的最大点特,惰性机制,要拿才给你拿一个,拿走了就没有值了
    # def func():
    #     print(111)
    #     yield 222
    #     yield 333
    #
    # a = func() #获取到生成器
    # a1 = (i for i in a)  #生成器
    # a2 = (i for i in a1) #生成器
    # print(list(a)) #[222, 333]
    # print(list(a1)) #[]
    # print(list(a2)) #[]
    #分析:为什么前面的a有值,后面的都没有值了?
    #解:因为a是源头,他从源头把数据给拿走了,所以后面再从前面拿的话就不会有值了,这就验证了生成器的惰性机制,你拿一个才给你一个,拿走了就没有了
    
    #那么后面还能不能获取到值? 答案是可以的,可以再做一个源头,再拿数据
    #例如:再定义一个a3获取生成器,再进行调用,这样子a2就有值了
    # def func():
    #     print(111)
    #     yield 222
    #     yield 333
    #
    # a = func() #获取到生成器
    # a1 = (i for i in a)  #生成器
    # a3 = func()
    # a2 = (i for i in a3) #生成器
    # print(list(a)) #[222, 333]
    # print(list(a1)) #[]
    # print(list(a2)) #[222, 333] #
    应用

    #面试题

    #题目:计算拿到的值是多少
    #求和函数
    # def add(a,b):
    #     return  a + b
    
    #生成器函数
    # def test():
    #     for r_i in range(0,4):
    #         yield r_i
    #
    # g = test() #获取到生成器
    #
    # for n in [2,10]:
    #     g = (add(n,i) for i in g)
    
    #上的for可以看成循环量词
    # for n in [2]:
    #     g = (add(n,i) for i in g)
    # for n in [10]:
    #     g = (add(n,i) for i in g)
    #因为是2还没取值,所以是叠加进去,将g换成上面
    #  g = (add(n,i) for i in (add(n,i) for i in 0,1,2,3)
    
    # print(list(g)) #20,21,22,23
    #分析:第一个函数是来求和得,第二个函数是生成器函数,没有打印值,然后到for循环,可以想象是2和10都执行了一次,但是因为生成器得惰性机制,然后执行2是没有值,所以是不关2的事情,执行10得时候才会执行,将10带进去算
    #最后的执行是这样:g = (add(10,i) for i in (add(10,i) for i in 0,1,2,3),所以就成10+10,10+11,10+12,10+13
    
    #提示:惰性机制,不到最后是不会拿值得
    
    
    #下面接着演示列表有多个值,但是它只会看最后面的那个,前面的会相加
    # def add(a,b):
    #     return  a + b
    
    #生成器函数
    # def test():
    #     for r_i in range(0,4):
    #         yield r_i
    # g = test() #获取到生成器
    # 
    # for n in [1,3,7]:
    #     g = (add(n,i) for i in g)
    #这个就是相当于叠加了3次
    # g = (add(7,i) for i in (add(7,i) for i in (add(7,i) for i in 0,1,2,3)
    
    # print(list(g))  #21,22,23,24
    #最后的运算是:(add(7,i) for i in (add(7,i) for i in (add(7,i) for i in 0,1,2,3) #将7带进去运算,把最后那个带进去算
    #首先是0+7,1+7,2+7,3+7,接着7+7,7+8,7+9,7+10,然后7+14,7+15,7+16,7+17
    面试题及讲解

    #生成器表达和列表推导式的区别

    1.生成器表达式比较省内存,列表推导式比较耗内存
    2.得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是生成器
  • 相关阅读:
    edge.js架起node.js和.net互操作桥梁
    Swift学习:闭包(Closures)
    swift UIAlertController教程
    linux配置IP的方法
    centos 6.5安装vncserver 并开启远程桌面
    CSS中各种居中方法
    jquery中的index方法和eq方法
    line-height的用法(一)
    第八章—BOM(一)
    第四章—变量,作用域和内存问题(一)
  • 原文地址:https://www.cnblogs.com/guoke-boy/p/12145614.html
Copyright © 2011-2022 走看看