我的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))
原文地址:https://www.cnblogs.com/yj0405/p/14071886.html