• 我的python学习之路-文件/函数/迭代器/生成器/推导式/高阶函数


    本文内容:

      一、文件操作

        1.1 基本操作

        1.2 字节流操作

        1.3 文件的扩展模式

        1.4  文件的相关方法           

      二、函数

        2.1 函数的基本格式

        2.2 函数的命名

        2.3 函数的参数

        2.4 return

        2.5 全局变量 和 局部变量

          2.6.函数名的使用

        2.7.函数的嵌套

        2.8.nonlocal (修改局部变量)

        2.9、闭包函数

        2.10 匿名函数 

      三、locals() 和 globals()

        3.1 locals() 获取当前作用域的变量

        3.2  globals() 获取全局变量

        3.3  利用globals批量创建全局变量

      四、迭代器

        4.1  可迭代性对象

        4.2 迭代器

      五、高阶函数

        5.1 map(func,Iterable) : 处理数据 

        5.2 reduce(func,Iterable)  计算数据

           5.3 filter(func,Iterable)  过滤数据

        5.4 sorted(Iterable , reverse=False , key = 函数)

       六、推导式

         6.1 列表推导式

        6.2.集合推导式

        6.3.字典推导式

      七、生成式

        7.1 生成器表达式

        7.2  生成器函数

    一 .文件操作

     对文件操作流程

    1. 打开文件,得到文件句柄并赋值给一个变量
    2. 通过句柄对文件进行操作
    3. 关闭文件 

    文件内容可以写入:1.字节流  2.字符串

    1.基本操作

    # 1.打开文件
    fp = open("lianxi.txt",mode="w",encoding="utf-8") 
    # 2.写入文件
    fp.write("把大象塞进去") 
    # 3.关闭文件
    fp.close() 
    # 1.打开文件
    fp = open("lianxi.txt",mode="r",encoding="utf-8")
    # 2.读取文件
    res = fp.read()
    # 3.关闭文件
    fp.close()
    print(res)

    2.字节流操作

    二进制字节流的应用场景: 在数据传输或者在数据存储时,使用的一种数据格式;
    多个字符放在一起叫做字符串,多个字节放在一起叫做字节流;

    将字符串和字节流(Bytes流)类型进行转换 (参数写成转化的字符编码格式)
       encode() 编码 :将字符串转化为字节流(Bytes流)
       decode() 解码 :将Bytes流转化为字符串

    字节流的格式:字节流语法格式(前面加b) : b"123"

    strvar = b"123"
    strvar = b"abc"
    # 中文不能在字符串前面加b,必须是ascii编码才能加;
    # strvar = b"你好" error
    print(strvar , type(strvar)) # b'123' <class 'bytes'>

    中文和字节流的转化

    # encode 编码
    strvar = "我爱你".encode("utf-8")
    print(strvar)
    
    # decode 解码
    res = strvar.decode("utf-8")
    print(res)
    
    # 三个字节表达一个中文字符
    s_bytes = b'xe7x88xb1'
    res = s_bytes.decode("utf-8")
    print(res)

    文件中写入字节流

    """mode = wb 代表写入的是字节流 , 不要指定任何编码集 """
    # 1.打开文件
    fp = open("lianxi2",mode="wb")
    strvar = "爱上一匹野马,家里没有草原"
    # 2.写入字节流
    fp.write(strvar.encode())
    # 3.关闭文件
    fp.close()

    从文件中读字节流

    """mode = rb 代表读取的是字节流 , 不要指定任何编码集 """
    # 1.打开文件
    fp = open("lianxi2",mode="rb")
    # 2.读取字节流
    res = fp.read()
    # 3.关闭文件
    fp.close()
    print(res)
    print(res.decode())

    小例子:模拟复制图片的过程

     1 # 打开原文件,读取其中的字节流
     2 fp = open("集合.png",mode="rb")
     3 res = fp.read()
     4 fp.close()
     5 print(res)
     6 
     7 # 把这些字节流写入到另外文件中
     8 fp = open("集合2.gif",mode="wb")
     9 fp.write(res)
    10 fp.close()
    View Code

    总结: 二进制字节流比如:图片,音频,视频 ... 数据使用二进制字节流进行拷贝

     3.文件的扩展模式

     read()  功能: 读取字符的个数(里面的参数代表字符个数)

     seek()  功能: 调整指针的位置(里面的参数代表字节个数)

      seek(0)   把光标移动到文件开头

      seek(0,2) 把光标移动到文件末尾

    tell() 功能: 当前光标左侧所有的字节数(返回字节数)

    1..r+ 先读后写
    fp = open("lianxi.txt",mode="r+",encoding="utf-8")
    # 先读
    res = fp.read()
    # 后写
    fp.write("456")
    # 在读
    fp.seek(0) #因为文件指针在文件末尾,指向开头
    res = fp.read()
    print(res)
    fp.close()
    2.r+ 先写后读

    r+模式打开后 文件指针默认指向文件的开头,马上写入内容,会覆盖原有的内容

    fp = open("lianxi.txt",mode="r+",encoding="utf-8")
    # 先写
    fp.seek(0,2) # 打开文件后默认指向文件开头
    fp.write("789")
    # 后读
    fp.seek(0)
    res = fp.read()
    print(res)
    fp.close()
    3.w+ 可写可读

    w+模式打开文件后,首先默认清空文件,所以先读后写没有意义;

    fp = open("lianxi2.txt",mode="w+",encoding="utf-8")
    # 先写
    fp.write("123")
    # 后读
    fp.seek(0)
    print(fp.read())
    fp.close()
    4.a+ 可写可读

    a+模式打开后 文件指针默认指向文件的末尾,所以可以直接写入内容

    fp = open("lianxi3.txt",mode="a+",encoding="utf-8")
    fp.write('abc')
    fp.seek(0)
    print(fp.read())
    fp.close()
    5.比对a+和r+两个模式之间的区别

        r+模式下 写入内容时,会随着光标位置的改变而替换原有的字符

        a+模式下 写入内容时,会强制把光标移动到文件的末尾

     

    6.seek ,read  , tell 三个方式的使用

      read(单位) 单位根据文件打开的模式而产生变化,如果带有b模式,读取的是字节的个数,否则读取的是字符的个数

      在移动seek时,小心光标移动到中文字符里,在读取内容时,产生无效的开始字节

    fp = open("lianxi.txt",mode="r+",encoding="utf-8")
    fp.seek(6)
    res = fp.tell() #6
    print(res)
    res = fp.read(3)
    print(res)
    res = fp.tell()
    print(res)
    fp.close()
    7. with语法 (上下文管理器)可以省略掉close操作
    with open("ceshimv.mp4",mode="rb") as fp1 , open("ceshimv2.mp4",mode="wb") as fp2:
        res = fp1.read()
        fp2.write(res)

    4.文件相关的方法

    1.刷新缓冲区 flush

    刷新缓冲区有一下几种情况

      (1). 当文件关闭的时候自动刷新缓冲区
      (2).当整个程序运行结束的时候自动刷新缓冲区
      (3)当缓冲区写满了 会自动刷新缓冲区
      (4)手动刷新缓冲区

     

     2.文件相关函数 

     1.readable()     功能: 判断文件对象是否可读
     2.writable()     功能: 判断文件对象是否可写
     3.readline()    功能 :读取文件一行内容

    (1) .先读取一行,如果内容不是空,打印这行数据,在读取下一行进行判断 

    with open("lianxi.txt",mode="r",encoding="utf-8") as fp:
        res = fp.readline()
        while res:
            print(res)
            res = fp.readline()

    (2).readline(2) 2个字符个数

    如果读取个数 > 当前行总个数 : 按照当前行读取
    如果读取个数 < 当前行总个数 : 按照个数读取

    4.readlines 功能:将文件中的内容按照换行读取到列表当中
    5.writelines()   功能:将内容是字符串的可迭代性数据写入文件中 参数:内容为字符串类型的可迭代数据
     6.truncate()     功能: 把要截取的字符串提取出来,然后清空内容将提取的字符串重新写入文件中 (字节)
    with open("lianxi4.txt",mode="r+",encoding="utf-8") as fp:
        fp.truncate(9)

     二.函数

     1.函数基本格式

    定义函数
    def 函数名():
        code1
        code2...
    调用函数
    函数名()

    2.函数的命名

     字母数字下划线,首字符不能为数字;

    严格区分大小写,且不能使用关键字;
    函数命名有意义,且不能使用中文哦;

     1.驼峰命名法:

      (1)大驼峰命名法:mycar => MyCar  每个单词首字符大写 (面向对象中 => 类)

      (2)小驼峰命名法: mycar => myCar  除了第一个单词首字符小写外,剩下的每个单词首字符大写 (用在函数中 .. )

     2.命名法: 单词和单词之间用_分开  mycar => my_car

    3.函数的参数

     函数的参数的种类: 1.形参   2.实参

    1.形参: 形式上的参数,在函数的定义处

    2.实参: 实际上的参数,在函数的调用处

    形参种类: 1.普通形参(位置形参) 2.默认形参 3.普通收集形参 4.命名关键字形参 5 关键字收集形参

    实参种类: 1.普通实参 2.关键字实参

     1.普通形参

    """hang,lie是普通形参(位置形参)"""
    def func(hang,lie):
        i = 0
        while i < hang:
            j = 0
            while j < lie :
                print("*" ,end="")
                j += 1
            print()
            i += 1
    # 调用函数
    """10,10是普通实参"""
    func(10,10)
    func(3,8)

    2.默认形参

     hang=10,lie=10 是默认形参,如果给与了实参,那么使用实参值,如果没有给与实参,那么使用默认值

    def func(hang=10,lie=10):
        i = 0
        while i < hang:
            j = 0
            while j < lie :
                print("*" ,end="")
                j += 1
            print()
            i += 1
            
    # 调用函数
    # func()
    func(5)
    # func(4,6)

    3.普通形参 + 默认形参

    hang普通形参,lie=10默认形参

    注意点:默认形参必须跟在普通形参的后面

    def func(hang,lie=10):
        i = 0
        while i < hang:
            j = 0
            while j < lie :
                print("*" ,end="")
                j += 1
            print()
            i += 1
    # func(5)
    func(5,6)

    4.关键字实参

     关键字实参的顺序可以任意颠倒

    注意点: 关键字实参必须写在普通实参的后面

    def func(hang,a,b,c,lie=10):
        i = 0
        while i < hang:
            j = 0
            while j < lie :
                print("*" ,end="")
                j += 1
            print()
            i += 1
    func(3,4,b=5,lie=7,c=6)    

    区别关键字实参和默认形参:

    1.在def定义处,使用的参数是默认形参

    2.在函数的调用处,使用的参数是关键字实参

    5.普通收集参数 

    功能: 专门用来收集那些多余的没人要的普通实参

    语法: 在参数的前面加上一颗星

    返回: 一个元组

    def func(a,b,c,*args):
        print(a,b,c) #1 2 3
        print(args) # (43,44)
    func(1,2,3,43,44)

    计算任意个数值的累加和

    1 def func(*args):
    2     print(args) # (1, 2, 3, 4, 5, 6, 7)
    3     total = 0 
    4     for i in args:
    5         total += i
    6     print(total)
    7 
    8 func(1,2,3,4,5)
    View Code

    6.关键字收集参数

       功能: 专门用来收集那些多余的没人要的关键字实参

    语法: 在参数的前面上加上二颗星星

    返回: 一个字典

    def func(a,b,c,**kwargs):
        print(a,b,c) # 1 4 3
        print(kwargs) #{'f': 5, 'z': 10, 'x': 30}
    func(a=1,c=3,f=5,b=4,z=10,x=30)

    做任意个数值的字符串拼接

     1 """
     2 颜值担当: 李雅琪
     3 靓丽女生: 王永捐
     4 普通颜值: 于盛林, 荷叶 , 吴洪昌
     5 """
     6 
     7 def func(**kwargs):
     8     strvar1 = ''
     9     strvar2 = ''
    10     dic = {"beautiful_boy":"颜值担当" , "beautiful_girl":"靓丽女生"}
    11     print(kwargs) # {'beautiful_boy': '李雅琪', 'beautiful_girl': '王永捐', 'common1': '于盛林', 'common2': '荷叶', 'common3': '吴洪昌', 'first': '菲菲', 'last': '石磊'}
    12     for k,v in kwargs.items():
    13         # print(k,v)
    14         # 如果该键在dic当中,说明是预定义角色,要获取该角色是什么 : 颜值担当   靓丽女生
    15         if k in dic:
    16             # 颜值担当 : 李雅琪 + '
    '
    17             # 靓丽女生 : 王永捐 + '
    '
    18             strvar1 += dic[k] + ":" + v + '
    '
    19         else:
    20             # 于盛林, 荷叶, 吴洪昌, 菲菲, 石磊,
    21             strvar2 += v + ","  
    22     
    23     
    24     print(strvar1.strip())
    25     print(  "普通颜值:"  ,  strvar2.strip(",")   )
    26     
    27 func(beautiful_boy = "李雅琪",beautiful_girl="王永捐",common1="于盛林",common2="荷叶",common3="吴洪昌",first="菲菲",last="石磊")
    View Code

     7 命名关键字形参

    如果是命名关键字形参 , 在调用函数时,必须使用关键字实参的方式调用

    (1) def func(a,b,*,c,d) 在星号后面定义的是命名关键字形参

    def func(a,b,*,c,d):
        print(a,b)
        print(c)
        print(d)
    func(1,2,c=3,d=4)

     (2) def func(*args,c,**kwargs) 在普通收集和关键字收集形参之间的是命名关键字形参

    print("<=========>")
    def func(*args,c,**kwargs):
        print(args)
        print(c)
        print(kwargs)
    func(1,2,3,4,45,a=1,b=2,c=3)

    8.* 和 ** 的使用方法

    (1) 在定义处: 负责收集打包数据
      * : 负责收集打包成元组
      **: 负责收集打包成字典
    (2) 在调用处: 负责打散解包数据
      * : 负责对list tuple str set 打散解包成单独的数据
      **: 负责对dic 打散解包成单独的键=值的形式

    # 函数的定义处
    def func(a,b,*,c,d):
        print(a,b)
        print(c,d)
    lst = [1,2] # 打散之后,把列表里面的元素一个个拿出来作为函数的参数进行调用
    tup = (1,2)
    set1 = {"aaa","bbb"}
    str1 = "ab" 
    dic = {"aaaa":1,"bbbb":2} # 获取的是字典的键
    # 函数的调用处 一颗星  *可迭代数据前面
    func(*dic,c=3,d=4) # func(1,2,c=3,d=4)
    # 函数的调用处 二颗星 **只能在字典前面修饰;
    dic = {"c":3,"d":4}
    func(1,2,**dic) # 把字典打散,抽离其中的键值对,变成 => c=3,d=4 关键字实参,作为参数调用函数;

    函数的参数定义顺序:
    普通形参(位置形参) => 默认形参 => 普通收集形参 -> 命名关键字形参 -> 关键字收集形参;

     4.return 

     return : 会把函数内部的值返回到函数的调用处;

    (1)return后面可以接 6大标准数据类型 ,还可以接函数,类,对象,如果没有自定义返回值,默认返回的None
    (2)执行完return之后,函数直接终止,后面的代码不执行;

    5.全局变量 和 局部变量

     局部变量: 在函数内部定义的变量是局部变量

    全局变量: 在函数外部或者在函数内部使用global定义的变量是全局变量

     作用域: 作用的范围

      局部变量: 在函数的内部
      全局变量: 横跨整个文件

     生命周期:变量存活的时间

      内置变量 > 全局变量 > 局部变量

     1.局部变量

    def func():
        # 创建一个局部变量
        a = 1
        # 获取局部变量
        print(a)
        # 修改一个局部变量
        a = 10
        print(a)
    func()
    # print(a) error

    2.全局变量

     方法一 :在函数外部定义的是全局变量

    # 创建一个全局变量
    b = 100
    # 获取全局变量
    print(b)
    # 修改全局变量
    b = 299
    print(b)
    
    def func():
        # 全局变量可以直接在函数内部调用
        print(b)
    func()

    方法二: 在函数内部定义全局变量,依赖global

    def func():
        # 声明一个全局变量c
        global c
        # 创建一个全局变量
        c = 99
    func()
    print(c)
    # 在函数内部修改全局变量
    d = 200
    def func():
        global d
        d = 300
    func()
    print(d) #300

    global总结:
    如果函数外部没有该全局变量,那么可以通过global在函数内部直接创建一个全局变量
    如果函数外部有该全局变量,那么可以通过global在函数内部修改当前全局变量

     6.函数名的使用

    python中的函数可以像变量一样,动态创建,销毁,当参数传递,作为值返回,作为容器中的元素.叫第一类对象.其他语言功能有限

     1 # 1.动态创建
     2 def func():
     3     print("我是func1 ... ")
     4 print(type(func))
     5 a = 1
     6 print(type(a))
     7 a = func
     8 a()
     9 
    10 # 2.动态销毁
    11 del a
    12 # a() error
    13 # func()
    14 
    15 # 3.当参数传递
    16 def func1(f):
    17     f()
    18 
    19 def func2():
    20     print("我是func2 ... ")
    21     
    22 func1(func2)
    23 
    24 # 4.作为值返回
    25 def func1(f):
    26     return f
    27 
    28 def func3():
    29     print("我是func3 ...")
    30 res = func1(func3)
    31 res()
    32 
    33 # 5.可以把函数作为容器中的元素
    34 def func1():
    35     print("我是func1 .. ")
    36 def func2():
    37     print("我是func2 .. ")
    38 def func3():
    39     print("我是func3 .. ")
    40 lst = [func1,func2,func3]
    41 for i in lst:
    42     i()
    43 
    44 
    45 # ### __doc__ 用来查看帮助文档
    46 def wash(something):
    47 
    48     """
    49 功能: 洗衣服的过程
    50 参数: something => 衣服
    51 返回值: 洗完的状态
    52     """
    53 
    54     print( "先脱{}".format(something) )
    55     print("放在桶里")
    56     print("到点洗衣液")
    57     print("泡水,搓一搓")
    58     print("穿上~")
    59     return "洗完了"
    60     
    61 wash("衣服")
    62 
    63 # __doc__ 函数.__doc__ 获取函数内部自定义文档;
    64 res = wash.__doc__
    65 print(res)
    View Code

    7.函数的嵌套

    互相嵌套的两个函数:
      外层函数即外函数
      内层函数即内函数

    def outer():
        inner()
        def inner():
            print("我是内函数 ... ")

    (1)内部函数不可以直接在函数外部调用
    (2)调用外部函数后,内部函数不可以在函数外部调用

    (3)内部函数可以在函数内部调用吗

    (4)内部函数在函数内部调用时,必须先定义函数,在调用函数,没有预加载机制


    三层函数嵌套,最外层是outer,中间层是inner ,最里层 smaller , 调用smaller函数

    def outer():    
        def inner():
            def smaller():            
                print("我是smaller函数 ... {}".format(id))
            smaller()
        inner()    
    outer()
    print(outer)

    LEGB 就近找变量原则:
    找寻变量的调用顺序采用LEGB原则(即就近原则)
    B —— Builtin(Python);Python内置模块的命名空间 (内建作用域)
    G —— Global(module); 函数外部所在的命名空间 (全局作用域)
    E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域)
    L —— Local(function);当前函数内的作用域 (局部作用域)
    依据就近原则,从下往上 从里向外 依次寻找

    8.nonlocal (修改局部变量)

    nonlocal 专门用来修改局部变量,符合LEGB原则,就近找变量,

    (1).找当前作用域上一层空间的变量值进行修改

    def outer():
        a = 1
        def inner():
            nonlocal a
            a = 10
            print(a) #10
        inner()
        print(a) #10
    outer() 

    (2).如果上一层不存在,继续向上一层空间进行寻找

    def outer():
        a = 199
        def inner():
            a = 201
            def smaller():
                nonlocal a
                a  = 200
                print(a) #200
            smaller()
            print(a) #200
        inner()
        print(a) #199
    outer()

    (3).直到最后找不到,直接报错

    a = 199 # 是全局变量, 而nonlocal用来修改局部变量;
    def outer():
        def inner():
            def smaller():
                nonlocal a
                a  = 200
                print(a)
            smaller()
            print(a)
        inner()
        print(a)
    outer()

    不通过 nonlocal 可以修改局部变量

    def outer():
        lst = [10,20,30]
        def inner():
            lst[0] = 100
        inner()
        print(lst) #[100, 20, 30]
    outer()

    9、闭包函数

      互相嵌套的两个函数,内函数使用了外函数的局部变量,

    外函数把内函数返回出来的过程,叫闭包,内函数叫做闭包函数

    原则:
    (1) 内函数使用了外函数的局部变量
    (2) 外函数将内函数返回return

    1.闭包函数基本语法

    def liyaqi_family():
        father = "李嘉诚"
        def hobby():
            print("我对钱没有兴趣,我只对捐钱感兴趣,这是我爸爸{}说的".format(father))    
        return hobby 
    res = liyaqi_family()
    res()

    2.闭包的复杂语法

     1 def liangruiqing_family():
     2     jiejie = "马蓉"
     3     meimei = "马诺"
     4     money = 1000
     5     
     6     def jiejie_hobby():
     7         nonlocal money
     8         money -= 600
     9         print("喜欢出轨,喜欢花钱,喜欢买包包,手表,GUCCI,chanel...家里的钱败光了,还剩下{}".format(money))
    10     
    11     def meimei_hobby():
    12         nonlocal money
    13         money -= 399
    14         print("我就喜欢在宝马里面哭,不喜欢在自行车上面撒欢~...家里的钱败光了,还剩下{}".format(money))
    15     
    16     def big_master():
    17         return [jiejie_hobby,meimei_hobby]
    18     
    19     # def func():
    20         # print(jiejie)
    21     # return func
    22     
    23     return big_master
    24 
    25 
    26 func = liangruiqing_family()
    27 # 获取姐姐函数
    28 jiejie = lst[0]
    29 jiejie() #家里的钱败光了,还剩下400
    30 # 获取妹妹函数
    31 meimei = lst[1]
    32 meimei() 家里的钱败光了,还剩下1
    View Code

    3.闭包的特点

        互相嵌套的两个函数形成了闭包;内函数使用了外函数的局部变量,
    该变量与内函数发生绑定,延长该变量的生命周期,直到该脚本运行结束.

    def outer(val):
        def inner(num):
            return val + num
        return inner
    func = outer(10)
    res = func(5)
    print(res) #15

    4.闭包的意义

    在做计数加1的过程当中,发现全局变量的值范围太大,导致可以被任意篡改,数据不安全

    clicknum = 0
    def func():
        global clicknum
        clicknum += 1
        print(clicknum)
    func()
    func()
    func()
    clicknum = 100
    func() #101

    出现的问题:单纯的局部变量不能累加1,

    def clicknum():
        x = 0
        x += 1
        print(x)
    clicknum()
    clicknum()
    clicknum()

    闭包的意义:

    闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装保护的作用.外部无法访问

    def clicknum():
        x = 0
        def func():
            nonlocal x
            x += 1
            print(x)
        return func
    func = clicknum() # func = 闭包函数func
    func()
    func()
    x = 100
    func() #3

    10.匿名函数

    用一句话来表达只有返回值的函数叫做匿名函数

     语法:  lambda 参数 : 返回值

    (1)无参的匿名函数

    def func():
        return "我是func1111"
    res = func()
    print(res)
    
    # lambda 改造
    func = lambda : "我是func1111"
    print(func())

    (2) 有参的匿名函数

    def func(num):
        return type(num)
    res = func([1,2,3])
    print(res)
    
    # lambda 改造
    func = lambda num :  type(num)
    print(func({"a":"1",'b':2}))

    (3) 带有判断条件的匿名函数

    三元(目)运算符 (只能在双向分支上可以使用,单项多项都不行)
    语法: 真值 if 条件表达式 else 假值 => 如果条件表达式是真的,返回真值,否则返回假值

    def func(num):
        if num % 2 == 0:
            return "偶数"
        else:
            return "奇数"
    res = func(11)
    print(res)
    
    # lambda 改造
    print("<=================>")
    func = lambda num : "奇数" if num % 2 == 1 else "偶数"
    print(func(102))

    三.locals() 和 globals()

    1.locals() 获取当前作用域的变量

      在函数外,获取的是打印之前所有全局变量

      在函数内,获取的是调用之前所有局部变量

    # 1.在函数外
    a = 1
    b = 2
    dic = locals()
    c = 3
    print(dic)  #a b c 都要打印 
    # 2.在函数内
    
    def func():
        a = 1
        b = 2
        dic = locals()
        c = 3
        print(dic)
        d = 4
    f = 5
    func() # #打印 a b
    g = 6

    2 . globals() 获取全局变量

    在函数外,获取的是打印之前所有全局变量
    在函数内,获取的是调用之前所有全局变量

    # 1.在函数外
    a = 1
    b = 2
    dic = globals()
    c = 3
    print(dic) ## a b c 都要打印
    # 2.在函数内
    
    def func():
        a = 1
        b = 2
        dic = globals()
        c = 3
        print(dic)
        d = 4
    f = 5
    func() ## 只打印 f
    g = 6

    3 .利用globals批量创建全局变量

    globals实现,通过字符串创建一个全局变量

    globals返回的是系统内置的一个字典

    通过往内置字典中添加键值对,实现全局变量的创建

    dic = globals()
    # 通过往内置字典中添加键值对,实现全局变量的创建
    dic["wangwen"] = "王文"
    print(dic)
    print(wangwen) #"王文"

    四、迭代器

    迭代器:能被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator  迭代器是对象)

    概念:迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的

    结果而继续的,单纯的重复并不是迭代

    特征:并不依赖索引,而通过next指针(内存地址寻址)迭代所有数据,一次只取一个值,

    而不是一股脑的把所有数据放进内存.大大节省空间

    1、 可迭代性对象

    如果一个对象中含有__iter__这个成员,说明该数据是可迭代性对象;

    ps:查看该对象中的成员,dir

    setvar = {"白金鸽","杨特","郝建康"}
    # 查看该对象中的成员,dir
    lst = dir(setvar)
    if '__iter__' in lst:
        print("该数据是可迭代性数据")
    print(lst)

    2、 迭代器

    如果是迭代器,一定是可迭代对象
    如果是可迭代对象,不一定是迭代器;

    1.如何变成一个迭代器

    setvar = {"白金鸽","杨特","郝建康"}
    # 1.如何变成一个迭代器
    it = iter(setvar) # 方法一
    it = setvar.__iter__() # 方法二
    lst = dir(it) 
    print(lst)

    2.如何判断一个迭代器 __iter__ + __next__ 

    if "__iter__" in lst and "__next__" in lst:
        print("该数据是迭代器")

    3.如何调用一个迭代器

     1 # 方法一
     2 res = next(it)
     3 print(res)
     4 res = next(it)
     5 print(res)
     6 res = next(it)
     7 print(res)
     8 # res = next(it) error
     9 # print(res)
    10 
    11 # 4.重置迭代器
    12 it = iter(setvar)
    13 # res = next(it)
    14 res = it.__next__()
    15 print(res)
    16 
    17 # 方法二
    18 print("<=========>")
    19 for i in it:
    20     print(i)
    21 # next(it) error 单项不可逆的过程
    22 
    23 # 方法三
    24 print("<=========>")
    25 setvar = {"白金鸽","杨特","郝建康","于盛林","杨业","王娟娟","草配线","孟凡伟"}
    26 it = iter(setvar)  # setvar.__iter__()
    27 for i in range(8):
    28     print(next(it))
    View Code

    五、高阶函数

    高阶函数 : 能够把函数当成参数传递的就是高阶函数

    1、map(func,Iterable) : 处理数据 

    功能:
      把Iterable中的数据一个一个的传递到func函数当中进行处理,处理之后的结果通过迭代器一个一个获取
    参数:
      func:内置或者自定义函数
      Iterable : 可迭代性数据(容器类型数据 range对象 迭代器)
    返回值:
      迭代器

    # (1) ["1","2","3","4"]  => [1,2,3,4]
    lst = ["1","2","3","4"]
    lst_new = []
    for i in lst:
        # print(int(i))
        lst_new.append(int(i))
    print(lst_new)
    
    
    # 使用map改写
    it = map(int,lst)
    for i in it:
        print(i,type(i))
    print(list(it))
    # (2) [1,2,3,4] => [5,10,15,20]
    lst = [1,2,3,4]
    lst_new = []
    for i in lst:
        res = i * 5
        lst_new.append(res)
    print(lst_new)
    
    # 使用map改写
    """ 注意点  : 参数和返回值必不可少"""
    def func(n):
        print(1111111111)
        return n * 5
    it = map(func,lst)

    2、reduce(func,Iterable)  计算数据

    功能:
        先把Iterable中的前两个数据拿出来,扔到func中做处理,得出一个结果,
         在拿当前结果和Iterable的下一个值在继续扔到func做计算,
         依次类推...
         直到最后返回结果.
    参数:
      func : 自定义函数
      Iterable : 可迭代性对象(容器类型数据 , range对象 , 迭代器)
    返回值:
      计算最后的结果

    #(1) [5,4,8,8] => 5488
    from functools import reduce
    
    def func(x,y):
        return x*10 + y
    lst = [5,4,8,8]
    res = reduce(func,lst)
    print(res,type(res))
    
    # lambda 改造
    print(reduce(  lambda x,y : x*10 + y  , lst))
    # (2) "5488" => 5488 不让使用int函数
    def func(x,y):
        return x*10 + y
    
    def func2(n):
        dic = {}
        for i in range(10):
            dic[str(i)] = i
        return dic[n]
        
    # 功能: "5488" => 5,4,8,8
    it = map(func2,"5488")
    # 功能: [5,4,8,8] => 5488
    res = reduce(func,it)
    print(res , type(res))

    3、filter(func,Iterable)  过滤数据

    功能:
      通过自定函数的返回值控制当前数据保留与否
      return True 代表保留
      return False 代表舍弃
    参数:
      func : 自定义的函数
      Iterable : 可迭代性数据(容器类型数据,range对象,迭代器)
    返回值:
      迭代器

    # lst = [1,12,435,234,122,2]  => 过滤掉偶数,保留奇数
    lst = [1,12,435,234,122,2] 
    lst_new = []
    for i in lst:
        if i % 2 == 1:
            lst_new.append(i)
    print(lst_new)
    
    # 使用filter进行改造
    def func(n):
        if n % 2 == 1:
            return True
        else:
            return False
    
    it = filter(func,lst)
    lst = list(it)
    print(lst)
    
    # 使用lambda 进行改造
    print(list(filter( lambda n : True if n % 2 == 1 else False , lst )))

    4、sorted(Iterable , reverse=False , key = 函数)

    功能:
      排序数据
    参数:
      Iterable : 可迭代对象 (容器类型数据 range对象 迭代器)
      reverse : 正序或者倒序 reverse = False (从小到大)
      key : 内置或者自定义方法
    返回值:
      排序后的数据(列表)

    # 1.从小到大
    lst = [-9,18,13,16,99,87]
    res = sorted(lst)
    print(res)
    
    # 2.从大到小
    res = sorted(lst,reverse=True)
    print(res)

    sort 和 sorted的区别:
      [sorted] 推荐
        1.sorted 可以对所有的容器类型数据排序
        2.返回一个新的列表
      [sort]
        1.sort 只能对列表这一个类型进行排序
        2.针对于原有的列表进行排序

    六 、推导式

    概念: 通过一行循环判断,遍历出一系列数据的方法就是推导式

    推导式种类三种:
      [val for val in Iterable] 列表推导式
      {val for val in Iterable} 集合推导式
      {a:b for a,b in iterable} 字典推导式

    1.列表推导式

    1.单循环推导式基本语法

    # 创建列表,内容为1~50
    lst = [ i for i in range(1,51) ]
    print(lst)

    2.带有判断条件的单循环推导式

    注意点: 在循环后面只能跟单项分支

    # 1 ~ 100 中的所有偶数保留到列表里
    lst = []
    for i in range(1,101):
        if i % 2 == 0 :
            lst.append(i)
    print(lst)
    
    # 改写推导式
    lst = [ i for i in range(1,101) if i % 2 == 0  ]
    print(lst

    3.多循环推导式基本语法

    lst1 = ["于盛林","荷叶","王永娟"]
    lst2 = ["李琦","朱培峰","刘灵镇"]
    
    lst = []
    for i in lst1:
        for j in lst2:
            lst.append(i + "" + j)
    print(lst)
    
    # 改写推导式
    lst = [ i + "" + j for i in lst1 for j in lst2 ]
    print(lst)

    4.带有判断条件的多循环推导式

    lst = []
    for i in lst1:
        for j in lst2:
            if lst1.index(i) == lst2.index(j):
                lst.append(i + "" + j)
    print(lst
    # 改写推导式
    lst = [ i + "" + j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j) ]
    print(lst)

    2.集合推导式

    """
    案例:
        满足年龄在18到21,存款大于等于5000 小于等于5500的人,
        开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)    
        把开卡的种类统计出来
    """
    data = [
        {"name":"李琦","age":22,"money":20000},
        {"name":"李雅琪","age":19,"money":12000},
        {"name":"吴洪昌","age":18,"money":5300},
        {"name":"王召","age":80,"money":4000},
        {"name":"王生父","age":81,"money":5400}
    ]
    
    setvar = set()
    for i in data:
        if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500:
            strvar = "尊贵VIP卡老{}".format(i["name"][0])
        else:
            strvar = "抠脚大汉卡老{}".format(i["name"][0])
        # 把对应的开卡格式存入到集合当中
        setvar.add(strvar)
    print(setvar)
    
    # 改写成集合推导式
    # 三运运算符  + for循环 => 集合推导式
    setvar = { "尊贵VIP卡老{}".format(i["name"][0]) if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else "抠脚大汉卡老{}".format(i["name"][0])  for i in data }    
    print(setvar)    
    View Code

    3.字典推导式

    (1)enumerate

    enumerate(iterable,[start=0])
    功能:  枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
    参数:
       iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
       start: 可以选择开始的索引号(默认从0开始索引)
    返回值: 迭代器

    lst = ["欢庆","尤佳","刘文波","黄长剑"]
    it = enumerate(lst)  # 默认从0开始索引
    it = enumerate(lst,start=1) # start = 1表示从1开始枚举配对;
    # 1.配合enumerate完成字典推导式操作
    dic = { k:v for k,v in enumerate(lst) }
    print(dic)
    # 2.直接通过dict强转
    dic = dict(enumerate(lst))
    print(dic)

    (2)zip(iterable, ... ...)

    功能: 将多个iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
      iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
    返回: 迭代器
    原则: zip的配对原则会按照相同的索引组合,如果没有相同的索引自动舍弃;

    # 1.配合zip完成字典推导式操作
    lst_key = ["zy","sxy","jyh"]
    lst_val= ["张印","孙翔宇","家营和"]
    dic = { k:v for k,v in zip(lst_key,lst_val) }
    print(dic)
    
    # 2.直接通过dict强转
    dic = dict(zip(lst_key,lst_val))
    print(dic)

    七、生成器

    生成器本质是迭代器,允许自定义逻辑的迭代器

    迭代器和生成器区别:
      迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑

    生成器可以用两种方式创建:
      (1)生成器表达式 (里面是推导式,外面用圆括号)
      (2)生成器函数 (用def定义,里面含有yield)

    1、生成器表达式

    # 生成器表达式
    gen = (i for i in range(100))
    print(gen) # generator
    
    # 调用生成器
    # 1.next
    res = next(gen)
    print(res)
    
    # 2.for + next (推荐)
    for i in range(3):
        print(next(gen))
        
    # 3.for  (慎用,防止数据量较大时,形成类似于死循环的效果)
    # for i in gen:
        # print(i)
    
    # 4.list (慎用,防止数据量较大时,内存溢出,出现蓝屏)
    lst = list(gen)
    print(lst)

    2、生成器函数 

    yield 类似于 return
    共同点在于:执行到这句话都会把值返回出去
    不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
          而return直接终止函数,每次重头调用.

    1.生成器函数语法

    def mygen():
        print("one")
        yield 1
        
        print("two")
        yield 2
        
        print("three")
        yield 3
        
    # 初始化生成器函数 => 返回生成器对象 , 简称生成器
    gen = mygen()
    res = next(gen)

    2.生成器优化写法

    def mygen():
        for i in range(1,101):
            yield "新制造的篮球球衣号码是{}".format(i)
            
    # 初始化生成器函数 => 返回生成器对象 , 简称生成器
    gen = mygen()
    
    # 先获取前30个数据
    for i in range(30):
        print(next(gen))

    3.send语法的使用

     send send发送值的时候,是给上一个yield

    next和send区别:
      next 只能取值
      send 不但能取值,还能发送值
    send注意点:
      第一个 send 不能给 yield 传值 默认只能写None
      最后一个yield 接受不到send的发送值

     1 def mygen():
     2     print("start ... ")
     3     res = yield "111"
     4     print(res)
     5     
     6     res = yield "222"
     7     print(res)
     8     
     9     res = yield "333"
    10     print(res)
    11     
    12     res = yield "444"
    13     print(res)
    14     print("end ... ")
    15     
    16 # 初始化生成器函数 => 返回生成器对象 , 简称生成器
    17 gen = mygen()
    18 # 第一次发送数据时,无脑加None
    19 res = gen.send(None)
    20 print(res)
    21 res = gen.send("我来了老妹2")
    22 print(res)
    23 res = gen.send("我来了老妹3")
    24 print(res)
    25 res = gen.send("我来了老妹4")
    26 print(res)
    27 # res = gen.send("我来了老妹5") error
    28 # print(res)
    View Code

    4. yield from 的基本使用

    yield from : 将一个可迭代对象变成一个迭代器返回

    def mygen():
        # yield [1,2,3,4,5]
        yield from [1,2,3,4,5]
    gen = mygen()
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))

     5、斐波那契函数(生成器)

    def fib(max):
        a,b = 0 , 1
        i = 0
        while i < max:
            # print(b)
            yield b
            a,b = b,a+b
            i += 1
    gen = fib(10)
    for i in range(5):
        print(next(gen))
  • 相关阅读:
    顺时针打印二维矩阵
    hbase的rowKey设计原则
    关于这段时间学习 EntityFramework的 一点感悟
    一次排序序号的补充
    我的第一段jQuery代码
    非常郁闷的 .NET中程序集的动态加载
    关于EF6的记录Sql语句 与 EntityFramework.Extend 的诟病
    排序更改
    ZhyjEye 简介
    js数组去重的4个方法
  • 原文地址:https://www.cnblogs.com/yj0405/p/14071886.html
Copyright © 2020-2023  润新知