生成器总结
1.语法上和函数类似,生成器函数和常规函数几乎是一样的。他们都是使用def语句进行定义,差别在于,生成器多次使用yield语句返回一个值,而常规函数使用一次return语句返回一个值。
2.自动实现迭代器协议,对于生成器,python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生stoplteration异常
3.状态挂起,生成器使用yield语句返回一个值,yield语句挂起该生成器函数的状态,保留足够的信息以便之后从它离开的地方继续执行。
函数可以理解成用来描述一个过程
什么是迭代器协议*****************忘记了,记得不够牢固
生成器只能遍历一次,这个很重要,我出错好几次都是因为这个原因
生成器表达式
g_l = (‘a‘ for i in range(10) ) ---圆括号
列表解析
l = [ ‘a‘ for i in range(10) ] -----方括号
def test(): for i in range(4): yield i t = test() t1 = ( i for i in t) print(list(t1) ) 结果[0, 1, 2, 3]
大前提:生成器产生的时候,不会进行任何操作,生成器取值是通过next方法
生成器只能走一遍(遍历一次)*****重要的事情说三次
t1 = ( i for i in t )
t2 = ( i for i in t1)
print(list(t1)) *******因为 t1 取空了,所以 t2 取不到值
print(list(t2))
结果
[ 0, 1, 2, 3 ]
[ ]
----------------------------------
l = [1, 2,3 ]
变成可迭代对象
l.__iter__() 也可以是 iter(l)
--------------------------
装饰器
装饰器本质就是函数,功能是为其他函数添加附加功能
原则是:
1不修改被修饰函数的源代码 ------------------(源代码被修改,有可能会产生不可预知的变化,因为你不知道源代码会在哪里被调用)
2不修改被修饰函数的调用方式
装饰器的知识储备:
装饰器 = 高阶函数 + 函数嵌套 + 闭包
高阶函数的定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
课上案例1
import time l = [1,2,3,4] def cal(): start_time = time.time() time.sleep(2) ret = 0 for i in l: ret += i stop_time = time.time() print(‘这是程序运行时间为%s‘%(stop_time-start_time)) return ret cal() 结果 这是程序运行时间为2.0003061294555664
高阶函数
def test(func): print(func) func() test(func)
添加时间功能
import time def foo(): print(‘你好啊,海绵宝宝‘) def test(func): print(func) start_time = time.time() func() stop_time = time.time() print(‘这是程序运行时间为%s‘ % (stop_time - start_time)) test(foo)
结果:
<function foo at 0x0000018662ED1E18>
你好啊,海绵宝宝
这是程序运行时间为0.0
test(foo)这样是违反里不改变函数调用方式,原来调用方式是foo()
返回值是一个函数(高阶函数)
def foo(): print(‘from the foo‘) def test(func): return func res = test(foo) print(res) ------------打印的是foo的内存地址 res() -----------运行foo函数
高阶函数的两个功能结合(因为多运行了一次foo,所以不合格)
import time def foo(): time.sleep(3) print(‘来自foo‘) def timmer(func): start_time = time.time() func() stop_time = time.time() print(‘这是程序运行时间为%s‘ % (stop_time - start_time)) 再写的时候报错是因为括号是中文模式写的 return func foo = timmer(foo) foo() 结果 来自foo 这是程序运行时间为3.000319004058838 来自foo
函数嵌套:函数内部再定义一个函数
函数嵌套例子:
def fater(name): print(‘父亲的名字是%s‘%name) def son(): print(‘from son‘) def granson(): print(‘from granson‘) granson() son() fater(‘海绵宝宝‘) 结果 父亲的名字是海绵宝宝 from son from granson
局部变量的寻找
def fater(name): print(‘父亲的名字是%s‘%name) def son(): print(‘我爸爸是‘+ name) print(locals()) ----------打印当前局部变量 fater(‘海绵宝宝‘) 结果 父亲的名字是海绵宝宝 {‘son‘: <function fater.<locals>.son at 0x000002851DB25510>, ‘name‘: ‘海绵宝宝‘}
其中son是内存地址
-----------------------------------------------------------------------------------------------------------------------------------
补充的知识点(在终端cmd模式演示)
一行赋值多个值------(解压序列,一 一对应的关系)
>>>>>> a,b,c = (1,2,3)
>>>>>>a
1
>>>>>>b
2
>>>>>>c
3
去开头和结尾的数字(终端演示)
l = [ 10, 2, 30, 47, 4, 6, 87, 45 ]
a,*_,c = l
>>>>>>a
10
>>>>>>c
45
>>>>>>>_ (下划线代表中间所有元素)
2, 30, 47, 4, 6, 87
也可以是这样
a,b,*_,c,d = l
>>>>>>a
10
>>>>>>b
2
>>>>>>c
87
>>>>>>d
45
取开头和结尾(索引方式)
a,d = l[0], l[-1]
a和b的值互换
a = 1 b = 2
第一种方法
x = a
a = b
b = x
第二种方法
a, b = b, a
--------------------------------------------------------------------------
这个是我们想要修饰器做到的效果,只运行一次。
import time def timmer(func): def wrapper(): start_time = time.time() func() stop_time = time.time() print(‘这是程序运行时间为%s‘ % (stop_time - start_time)) return wrapper def test(): time.sleep(3) print(‘test程序运行完毕‘) res = timmer(test) 返回的是wrapper的内存地址 res() 这里执行的是wrapper() 结果 test程序运行完毕 这是程序运行时间为3.000622272491455
然后调用方式改一下,就是我们要修饰器要达到的效果。
import time def timmer(func): def wrapper(): start_time = time.time() func() stop_time = time.time() print(‘这是程序运行时间为%s‘ % (stop_time - start_time)) return wrapper def test(): time.sleep(3) print(‘test程序运行完毕‘) test = timmer(test) 返回的是wrapper的内存地址 test() 执行的是wrapper() 结果 test程序运行完毕 这是程序运行时间为3.0006837844848633
可以在要修饰的函数前写上 @timmer 就相当于 test= timmer(test)
写的时候出错有两点:
1.函数名称写错(没有技术含量的错误)
2.在修饰器的返回值那里return wrapper 写成 return wrapper()
加上返回值,加上参数。要求
加上参数:(*args, **kwargs)用来接收不确定参数格式
验证功能大型例子
第一次写
# name = ‘bili‘ # pawd = 123 #为了纪念伟大的bili # shopping_car_list = [‘皮鞭‘,‘蜡烛‘,‘内裤‘] ‘‘‘ 现在是要在所有的程序前面加上用户验证,利用装饰器功能。 ‘‘‘ def zsq(func): #装饰器 def yhyz(*args,**kwargs): #用户验证 name = input(‘请输入用户名字‘).strip()#应该是除去空白 pawd = input(‘请输入密码‘).strip() if name == ‘bili‘ and pawd == ‘123‘: #出现一次缩进错误 print(‘欢迎进入哲学天堂‘) func() #***********忘记写了 else: print(‘密码或者用户名错误‘) return yhyz #问题一为什么只是在index()里,没有进入下一层 #少了一步是运行该函数func() #问题二,为什么没有将名字传给index()里 @zsq def index(): #程序的主页 print(‘欢迎%s来到哲学天堂‘) @zsq def home(): #用户的家目录,也可以理解成个人信息设置 print(‘请完善%s信息‘) @zsq def shopping_car(): #购物车 print(‘你的购物车有皮鞭,蜡烛,内裤‘) #怎么传一个列表给购物车
index() home() shopping_car()
#问题二,为什么没有将名字传给index()里,是因为引用方法不对
+用户只需要登入一次功能
+用户名称显示在其他被修饰程序中功能
#问题二,为什么没有将名字传给index()里 #错误显示没有找到name,index应该是要找全局变量的 dic_user = {‘name‘: None, ‘login‘: False} #定义一个全局变量来保存登入状态 def zsq(func): # 装饰器 def yhyz(*args, **kwargs): # 用户验证 if dic_user[‘name‘] and dic_user[‘login‘]: #如果之前登入过了就不用再登入了,这句话是真的情况下 ret = func(*args, **kwargs) return ret name = input(‘请输入用户名字‘).strip() pawd = input(‘请输入密码‘).strip() if name == ‘bili‘ and pawd == ‘123‘: dic_user[‘name‘] = name dic_user[‘login‘] = True print(‘欢迎进入哲学天堂‘) ret = func(*args, **kwargs) return ret else: print(‘密码或者用户名错误‘) return yhyz @zsq def index(*args, **kwargs): #程序的主页 print(‘欢迎%s来到哲学天堂‘%dic_user[‘name‘]) #这里要变量要到全局的找,之前一直失败是因为这里找的不对 @zsq def home(): #用户的家目录,也可以理解成个人信息设置 print(‘请完善%s信息‘) @zsq def shopping_car(): #购物车 print(‘你的购物车有皮鞭,蜡烛,内裤‘) #这么传一个列表给购物车,这个列表是一个保存大一个文件里,当是bili登入时才显示。 **这个功能下次写吧** index() print(dic_user)
+用户不在是一个人,而是多个。
user_id = [ {‘name‘: ‘nec‘, ‘pawd‘: ‘123‘},#nec老中医,战场搅屎棍 {‘name‘: ‘aoe‘, ‘pawd‘: ‘123‘}, {‘name‘: ‘bili‘, ‘pawd‘: ‘123‘}, {‘name‘: ‘acfun‘, ‘pawd‘: ‘123‘}, ] dic_user = {‘name‘: None, ‘login‘: False} def zsq(func): # 装饰器 def yhyz(*args, **kwargs): # 用户验证 if dic_user[‘name‘] and dic_user[‘login‘]: ret = func(*args, **kwargs) return ret ipname = input(‘请输入用户名字‘).strip() ippawd = input(‘请输入密码‘).strip() for i in user_id: if ipname == i[‘name‘] and ippawd == i[‘pawd‘]: #这里出错了TypeError: list indices must be integers or slices, not str dic_user[‘name‘] = ipname #类型错误:列表索引必须是整数或片,而不是str。 dic_user[‘login‘] = True #不应该时user_id 而是 i才对,i才是元素,而user_id是整个列表 print(‘欢迎进入哲学天堂‘) ret = func(*args, **kwargs) return ret else: print(‘密码或者用户名错误‘) return yhyz @zsq def index(): #程序的主页 print(‘欢迎%s来到哲学天堂‘%dic_user[‘name‘]) @zsq def home(): #用户的家目录,也可以理解成个人信息设置 print(‘请完善%s信息‘%dic_user[‘name‘]) @zsq def shopping_car(): #购物车 print(‘你的购物车有皮鞭,蜡烛,内裤‘)
用户登入类型(懒)