一、列表生成式和生成器
列表生成式和生成器都属于可迭代对象
列表生成式:生成一个列表,区别列表生成器range,需要进行转换list(range(start,end,step))
生成器:generator
1.列表生成式
List Comprehensitons,是Python内置的用来创建列表的工具
语法:[元素 for循环 条件判断]
代码演示:
#语法:[新列表的元素规律 for循环 条件判断],条件判断根据具体的需求可以省略 #1.需求:生成一个列表list1 = [1,2,3,4,5,6,7,8,9] list1 = list(range(1,10)) print(list1) #2.需求:生成一个列表list2 = [1,4,9,16,25,36,49...81] #方式一:通过追加自己实现 newList1 = [] for x in range(1,10): newList1.append(x ** 2) print(newList1) #方式二:列表生成式 newList2 = [i ** 2 for i in range(1,10)] print(newList2) #[1, 4, 9, 16, 25, 36, 49, 64, 81] #3.加上条件判断 newList3 = [i ** 2 for i in range(1,10) if i % 2 == 0] print(newList3) #4.需求:生成一个列表,其中的元素是1~20之间的偶数 newList4 = [i for i in range(1,21) if i % 2 == 0] print(newList4) #5.可以使用嵌套循环,生成一个全排列 """ 1,2,3,4 从中取出3个进行排列 123 321 213 231 234 342 432 。。。 """ list2 = [m + n for m in "ABC" for n in "XYZ"] print(list2) #['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] """ for m in "ABC" for n in "XYZ" print(m + n) AX AY AZ BX BY BZ CX CY CZ """ #6.for循环可以同时遍历两个数据 d = {"A":"x","B":"y","C":"z"} for k,v in d.items(): print(k,"=",v) list3 = [k + "=" + v for k,v in d.items()] print(list3)#['A=x', 'B=y', 'C=z'] #练习:使用列表生成式将下面列表中的所有单词改为小写 l = ["hello","IBM","abc","Good"] #方式一 newList1 = [] for word in l: newList1.append(word.lower()) print(newList1) #方式二 newList2 = [word.lower() for word in l] print(newList2) l = ["hello","IBM",18,"abc","Good"] #存在的问题:int没有lower,没有isalpha,所以如果列表中存在整型,则无法进行转换 #newList3 = [word.lower() for word in l if word.isalpha()] #print(newList3) #isinstance():判断一个变量是否是某种指定的数据类型 num = 10 print(isinstance(num,int)) s = "hello" print(isinstance(s,str)) #解决方案:在转换之前,先进行判断,判断元素是否是字符串 newList3 = [word.lower() for word in l if isinstance(word,str)] print(newList3) """ 总结: [元素的规律 for循环 if判断] 执行顺序:第一步:for循环 第二步:if判断 第三步:元素的规律 注意:if'判断只能判断for循环遍历出来的元素 """
2.生成器
生成器:生成具有一定内容的容器【generator】
作用:为了解决快速的生成一批数据,会占用大量的内存的问题,引入了生成器的机制,用来生成指定一批数据的算法,当需要使用数据的时候,生成器直接生成
定义生成器的方式
方式一:将列表生成式中的[]改成()
方式二:通过函数和关键字yield生成
代码演示:
#1. ge1 = [x for x in range(1,10)] #列表生成式,list print(type(ge1)) ge2 = (x for x in range(1,10)) #生成器,generator print(type(ge2)) #2.生成器本质上还是一个容器,其中可以存储多个数据 #特殊:除了可以使用for遍历之外,还可以使用next()遍历 print(ge2) """ print(next(ge2)) print(next(ge2)) print(next(ge2)) """ #补充:如果一个for循环只是为了控制循环的次数,则其中的变量可以用下划线代替 for _ in range(0,9): print(next(ge2)) #注意:如果一个生成器中的元素通过next全部遍历完成之后,再次调用next,则会报错StopIteration #print(next(ge2)) #StopIteration 停止迭代 """ 1 2 3 4 5 6 7 8 9 """ #注意:区别于list等的遍历【list等的遍历每次都是从头开始遍历,但是,生成器只要遍历一次,下一次遍历则没有结果】 for num in ge2: print(num) print("****************") #2.通过函数和yield def test(n): for i in range(1,n + 1): print("111",i) yield i #暂停 print("222",i) r = test(10) print(r) #<generator object test at 0x000001870CA59200> """ for x in r: print("~~~~",x) """ print(next(r)) print(next(r)) print(next(r)) """ 111 1 1 222 1 111 2 2 222 2 111 3 3 """ #工作原理:函数生成器执行到yield的时候会暂停,会将yield后面的值返回,并将yield前后的代码屏蔽 #当遍历生成器的时候,才会再去执行被屏蔽掉的代码
二、可迭代对象和迭代器
1.可迭代对象
可以直接作用于for循环的对象统称为可迭代对象:Iterable
可以直接作用于for循环的数据类型有:
a.一类是集合数据类型:包括list,tuple,dict,set,string
b.一类是生成器generator【包括()和yield】
通过isinstance()判断一个对象是否是可迭代对象
代码演示:
#第一步:导入模块 from collections import Iterable print(isinstance([],Iterable)) print(isinstance((),Iterable)) print(isinstance({},Iterable)) print(isinstance("hello",Iterable)) print(isinstance((x for x in range(1,9)),Iterable)) print(isinstance(10,Iterable)) print(isinstance(True,Iterable))
2.迭代器
不但可以直接作用于for循环,还可以使用next()获取元素值,被称为迭代器:Iterator
通过isinstance()判断一个对象是否是迭代器
代码演示:
from collections import Iterator print(isinstance([],Iterator)) print(isinstance((),Iterator)) print(isinstance({},Iterator)) print(isinstance("hello",Iterator)) print(isinstance((x for x in range(1,9)),Iterator)) print(isinstance(10,Iterator)) print(isinstance(True,Iterator)) #不能使用next遍历,但是可以使用for遍历的数据类型就是可迭代对象【注意:生成器可以使用for或者next遍历】 #迭代器一定是可迭代对象,但是,可迭代对象不一定是迭代器 print("*********") #虽然;list,tuple,dict以及string都不是迭代器,可以通过iter()将其转换为迭代器 print(isinstance(iter([]),Iterator)) print(isinstance(iter(()),Iterator)) print(isinstance(iter({}),Iterator)) print(isinstance(iter("abc"),Iterator)) #区分可迭代对象和迭代器 #补充:迭代器的遍历 ge = (x for x in range(34,100)) """ for num in ge: print(num) """ #工作原理:使用next遍历,当所有的元素遍历完成,则报错StopIteration,作为条件 while True: try: #监控区:查看其中的代码有没有异常,如果有异常,则代码跳到except分支中执行 num = next(ge) print(num) except StopIteration: break
三、闭包
如果在一个函数的内部再定义一个新的函数,外部的函数被称为外部函数,里面函数被称为内部函数
语法:
def 外部函数函数名(参数):
函数体1
def 内部函数函数名(参数:
函数体2
return 内部函数的函数名
说明:如果一个外部函数中定义了一个内部函数,并且外部函数的返回值是内部函数的引用,这样就构成了闭包
代码演示:
四、变量的作用域
1.概述
变量的作用域:指的是一个变量可以被访问的范围
注意:程序中的变量并不是在任意位置可以任意访问,访问权限取决于该变量被定义的位置
2.使用
2.1作用范围划分
分类:
L:Local,局部作用域
E:Enclosing,函数作用域【外部函数和内部函数之间】
G:Global,全局作用域
B:Built-in,内置作用域或者內建作用域
2.2查找规则
前提:当代码中的变量重名的情况下,按照L---->E----->G----->B方式查找
代码演示:
#变量的作用域 #1.如果变量不重名的情况下 #在内部函数中可以任意访问,主要是通过变量名进行匹配 #全局作用域 num1 = 10 def outter1(): #函数作用域 num2 = 20 def inner1(): #局部作用域 num3 = 30 print(num1,num2,num3) return inner1 f1 = outter1() f1() #2.如果变量重名的情况下 #在内部函数中访问变量,优先访问内部函数中的变量,其次是函数作用域的变量,最后才是全局作用域的变量 num = 10 def outter2(): #num = 20 def inner2(): #num = 30 #就近原则 print(num) return inner2 f2 = outter2() f2() print("*********") #3. #3.1 def func(): n1 = 10 func() #print(n1) #3.2 if True: n2 = 20 print(n2) #3.3 for i in range(1,5): n3 = 40 print(n3) #不建议直接访问变量i print(i) #3.4 n = 0 while n < 1: n4 = 25 n += 1 print(n4) """ 结论: 1.在Python中,只有模块【module】,类【class】,函数【function】会引入新的作用域 2.一些普通的语句,比如if,while,for,try-excpet都不会引入新的作用域【在语句其中定义的变量,在外面仍然可以访问】 """
2.3全局变量和局部变量
全局变量:定义在函数外面的变量【拥有全局的作用域】
局部变量:定义在函数内部的变量【只能在函数内部使用】
生命周期:全局变量大于局部变量
代码演示:
#1.不重名 total = 0 #全局变量 def func(): num = 10 #局部变量 print("~~~",num,total) func() print("outter",total) #2.重名 n = 23 def show(): #print(n) #unboundLocalError: local variable 'n' referenced before assignment n = 40 print(n) show() print("outer",n)
2.4global和nonlocal关键字的用法
global:全局
#当全局变量和局部变量重名,在函数的内部,在局部变量定义之前使用全局变量,统统都需要声明 num = 1 def fun1(): #使用global向编译器做一个声明,告诉编译器:此处需要访问的就是全局变量 global num print(num) num = 123 print(num) fun1() #练习: #全局变量 a = 10 def test(): global a #局部变量 a = a + 1 print(a) test()
nonlocal:不是局部的
#前提:nonlocal定义在闭包中【函数作用域】 #nonlocal:将一个变量的局部作用域扩大到函数作用域,在整个外部函数中被可以被访问 x = 0 #全局作用域 def outer(): x = 1 #函数作用域 def inner(): nonlocal x x = 2 #局部作用域 print("inner:",x) #调用函数 inner() print("outer:",x) outer() print("gloabl:",x) """ inner: 2 outer: 1 ---->2 gloabl: 0 """
五、装饰器
def now(): print("hello") #思考问题:在不修改原函数的基础上,给原函数增加新的功能 #解决方案:装饰器
装饰器【Decorator】,如果要增强某个函数的功能,但是不能修改原函数,这种在代码运行期间给函数动态添加功能的操作机制被称为装饰器
本质:就是一个闭包,将一个函数作为外部函数的参数,返回一个函数
应用场景:1.统计函数执行时间, 2.执行函数结束之后的清理行为 3.权限校验,4.缓存 5.面向对象
使用最多的是直接使用系统的装饰器
代码演示:
#1.简单的装饰器 def test(): print("hello") #装饰器的书写语法 #a.书写闭包 #b.给外部函数设置参数,实参需要传一个函数【需要被增加功能的函数】 def outer1(func): def inner1(): #注意:先调用原函数还是先增加新功能,都行 #c.调用需要被增强功能的函数 func() #d.增加新的功能 print("abx") return inner1 f = outer1(test) #func = test f() """ outer被称为装饰器 新增加的功能可以写在原函数调用的前面或者后面 """ #需求:增加九九乘法表 def show(n): for i in range(n): print(i) def outer2(func): def inner2(): #新增的功能 for i in range(1,10): for j in range(1,i + 1): print("%dx%d=%d" % (j,i,i * j),end=" ") print("") #调用原函数 func(10) return inner2 f2 = outer2(show) f2() print("******************************************") #2.有参数的装饰器 def getAge(age): print(age) """ getAge(10) getAge(-38) """ #需求:在不修改原函数的基础上,进行数据的过滤【检验】 #当输入的age为负数时,将其改为正数 def wrapper(func): def inner(num): #增加新的功能:过滤负数 if num < 0: num = abs(num) #调用原函数 func(num) return inner f1 = wrapper(getAge) f1(10) f1(-20) #注意:如果原函数有参数,需要在装饰器的内部操作参数,则需要给inner设置参数 print("******************************************") #3.简化装饰器:使用 @ 将装饰器直接应用到需要被增强功能的函数上 #语法:@装饰器的名字 def wrapper1(func): def inner(): print("hfaj") func() return inner @wrapper1 def test(): print("hello") test() #使用@之后,则直接调用原函数,就可以使用装饰器 #注意:使用@之后,装饰器必须出现在原函数出现之前 print("******************************************") #4.带有不定长参数的装饰器 #如果要给多个函数增强同一个功能,给inner设置不定长参数 def wrapper2(func): def inner(*args,**kargs): print("hello") func(*args,**kargs) return inner @wrapper2 def show1(num1): print(num1) show1(10) @wrapper2 def show2(num1,num2,num3): print(num1,num3,num2) show2(10,3,54) print("******************************************") #5.特殊情况:多个装饰器同时作用于同一个函数 def wrapper11(func): def inner11(): print("第一个装饰器") func() return inner11 def wrapper22(func): def inner22(): print("第二个装饰器") func() return inner22 @wrapper11 @wrapper22 def check(): print("num") check() #check() #结论:如果多个装饰器作用于同一个函数,则按照从上往下的顺序执行,但是,不管有多少个装饰器,原函数只会被调用一次