第一个装饰器


1 #装饰器的组成结构为:高阶函数+嵌套函数 2 import time 3 def timer(func): #timer(test1) func = test1 4 def deco(*args,**kwargs): 5 first_time =time.time() 6 func(*args,**kwargs)#run test1 7 stop_time =time.time() 8 print('the func run time is %s' %(stop_time-first_time)) 9 return deco 10 #如果要装饰的函数有参数的话就要通过,*args **kwargs 来进行处理 11 @timer #等价于 test1 = timer(test1) = deco 给要添加该功能的函数头部添加 @timer 12 def test1(): 13 time.sleep(3) 14 print('in the test1') 15 @timer 16 def test2(name,age,sex): 17 print('name:%s\n''age:%s\n' 'sex:%s\n' %(name,age,sex)) 18 test1() 19 test2("zhangsan",23,"n")
高阶装饰器案例
1 import time 2 user,passwd = 'zhangsan','abc123' 3 def auth(auth_type): 4 print("auth func:",auth_type) 5 def outer_warpper(func): 6 def wrapper(*args, **kwargs): 7 print("wrapper func args:",*args, **kwargs ) 8 if auth_type=="local": 9 username = input("username:").strip() 10 password = input("password:").strip() 11 if user == username and passwd == password: 12 print("\033[32;1m user has passed authentication\033[0m") 13 res = func(*args, **kwargs) 14 print("-----after authentication-----") 15 return res 16 else: 17 exit("\033[31;1m invalid username or password \033[0m") 18 elif auth_type=="ldap": 19 print("enter ldap module ……") 20 return wrapper 21 return outer_warpper 22 23 def index(): 24 print("welcome to index page") 25 @auth(auth_type="local") #由于此时装饰器中参数,故而会先执行装饰器,等执行装饰器之后才会再次返回内存地址 26 def home():#wrapper 27 print("welcome to home page") 28 return "from home" #只有上面装饰器中有结果返回时,才会有返回 29 @auth(auth_type="ldap") 30 def bbs(): 31 print("welcome to bbs page") 32 index() 33 home() 34 bbs()
列表生成式
作用
1、代码简单 2、用于提高格调
如:
b =[ i*2 for i in range(10)] #b =[ func(i) for i in range(10)]
Print(b) #结果为:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
在i*2的地方可以换成函数等
生成器(generator)
如: c = (i*2 for i in range(10)) # 就会生成一个生成器
for i in c:
print(c)
生成器和列表生成的区别:
列表生成式是将所有的数据都放进内存中,而生成器是先通过算法,只有调用时才会生成数据;列表可以查看每一个,但生成器是因为还没有生成所以才会不支持
生成器 省内存是通过只存在当前数据,并且下面的一个可以通过c.__next__()就可以
如果通过print(f.__next__()) 取出generator中的数据,如果取出的数据超出了生成器所生成的数据,那么解释器就会出现 异常
1 #斐波那契数列 2 def fib(max): 3 n,a,b = 0,0,1 4 while n<max: 5 #print(b) 6 yield b #将上面的print(b)换成yield b 就会将这个斐波那契数列变成一个 生成器(generator) 7 a,b =b,a+b #等价于:t=(a,a+b) 8 # print(b) 9 n=n+1 10 return "done" #出现yield 就表示是一个生成器而不是一个函数, 异常时会返回return 值 11 12 f=fib(10) 13 print(f.__next__())#f.__next__() 表示唤醒generator 因为generator中有一个算法,会自动计算出值, 14 # 所以才会输出值,如果没有之前算出的值那么就会返回一个none 15 print(f.__next__()) 16 print("-----进入-------")# print(f.__next__()) 好处是:可以干其他的事情 不必等到函数执行完,并且可以随时进入使用 17 print(f.__next__()) #如果想回来直接print(f.__next__())就可以回到generator 18 print(f.__next__()) 19 print("-------中断------") 20 print(f.__next__()) 21 print("-----start loop --------")
生成器的并行处理
#协程 比线程更小的单位 寄生在线程里 import time def consumer(name): print('%s准备吃包子了!'%name) while True: baozi =yield #没有返回值 所以为空 print("包子[%s]来了,给[%s]吃了!"%(baozi,name)) c=consumer("张三") #由于此时是生成器,故而如果是函数的话就会执行往下走, # 但是现在有yield,故而当执行完之后,才会转换成生成器,当执行完c.__next__()之后才会向下执行到yield返回 c.__next__() #只唤醒generator 等下一次c.__next__()时,才会返回一个值,如果为空就为none #c.send("韭菜馅") #先唤醒generator,再赋值作为yield的返回值 #c.__next__() def producer(name): c =consumer("A")#给两个顾客,A和B开始做包子 c2 =consumer("B") c.__next__()#准备吃包子 c2.__next__()#如果没有两个next就相当于只是将函数变成生成器 但不会执行下面,只有当进行next之后,才会进行yield中断 print("%s开始做包子啦!"%name) for i in range(10): time.sleep(1) print("做了1个包子,分两半!") c.send(i)#由于是通过generator来进行存储,故而当速度足够快时,此时就相当于多线程 c2.send(i) producer("lisi")
迭代器(Iterator)
我们已经知道,可以直接用作for循环数据类型有以下几种:
一类是集合数据类型,如:list、dict、set(集合)、tuple、str等;
一类是generator,包括生成器和带yield的generator function
这些可以直接作用于for循环的对象成为可迭代对象:Iterable,可以用isinstance()判断一个对象是否为Iterable对象:
可以被next()等价于__next__()函数调用并不断返回下一个值的对象称为迭代器:Iterator
生成器都是Iterator对象,但list、dict、str、虽然是Iterable,却不是Iterator,把list、dict、str等Iterable变成Iterator可以使用Iter()函数
a=[1,2,3,4,5]
iter(a) #此时就会变成一个迭代器
b=iter(a) #通过将迭代器赋给b然后可以使用__next__()函数
b.__next__()
b.__next__()
为什么list、dict、tuple、str等数据类型不是Iterator?
这是因为python的Iterator表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,知道没有数据是抛出StopIteration错误,可以把这个数据流看做有序序列,但我们却不能提前知道序列的长度,只能不断地通过next()函数实现按需求计算下一个数据,所以Iterator计算是一个惰性的,只有在需要返回下一个数据的时候才会计算。
Iterator 甚至可以表示一个无限大的数据流,例如全体自然数,而list却永远不能存储全体自然数的
内置方法:
1 res = filter(lambda n:n>5,range(10)) # filter 过滤 对满足要求的打印出来 2 res =map(lambda n:n*n,range(10)) #map 对传入的每一个数据都按照某种规则进行处理,然后再打印出来,等价于:列表生成式:[i*i for i in range(10)]
1 import functools 2 res =functools.reduce(lambda x,y:x*y,range(1,5)) # 阶乘 reduce在functools中 3 res =functools.reduce(lambda x,y:x+y,range(1,5)) # 相加 4 print(res)
hash (通过映射就可以将key:value变成固定的数字对应 这种映射称之hash)
如果要将一个数字存入内存,写几就是几,如果是字符串时,就会通过hash转换成一个固定的数字,不管输出多少次,都会是同一个值 然后再从小到大排序,再通过算法查找即可
1 >>> hash("1234") 2 -1376222673 3 >>> hash(1) 4 1 5 >>> hash("china") 6 1594593131
json 和pickle
Json和pickle 两种模块的使用
作用:将不是字符串的类型转换成字符串并保存并且两者使用方法完全一样
区别:json只能处理简单的文件 比如:list、dictionary、tuple , Json在任何语言中都能用,比如在java中也可以使用
缺点:不能处理复杂的工作,比如:函数
Pickle比json功能强大,不但可以处理list、dictionary等还可以处理复杂的文件,比如函数等
缺点: pickle只能在python的本语言中进行使用,比如在java中; pickle使用处理之后保存只能为byte类型不能保存成字符串
处理方法:通过代码转换来处理,比如文件中的 “wb”或者”rb”就可以
1 序列化程序: 2 #用pickle 会报错 TypeError: write() argument must be str, not bytes故而可通过 wb处理 3 def sayhi(name): 4 print("hello,",name) 5 info = { 6 "name":"zhangsan", 7 "age":22, 8 "func":sayhi 9 } 10 with open("b.text","wb") as f: 11 f.write(pickle.dumps(info)) #等价于:pickle.dump(info ,f) 12
反序列化程序: 13 """AttributeError: Can't get attribute 'sayhi' on <module '__main__' from ' 14 F:/pycharm/day5/json反序列化.py'> 说明;没有找到函数sayhi函数的入口 15 处理方式:将那个函数拷贝一份放到反序列化中,然后再进行处理""" 16 def sayhi(name): 17 print("hello,", name)#在进行反序列化处理时,是将整个函数的内存地址都进行处理,也就是说可以将拷贝过来的函数内容修改,但是不能修改函数名 18 print("hello2,", name) 19 print("haha") 20 21 import pickle 22 with open("b.text","rb") as f: 23 data =pickle.loads(f.read()) #data =pickle.load(f) 24 # data1 =f.read() 25 print(data["func"]("zhangshuai"))# 对函数进行赋值
pycharm 知识充电
Dictionary在pycharm中就是一个文件夹,放置资源文件,对应于在进行JavaWeb开发时用于放置css/js文件的目录,或者说在进行物体识别时,用来存储背景图像的文件夹。该文件夹其中并不包含_ _ init.py_ _文件
python package(包):(下面可以放一堆模块)用来从逻辑上组织模块(.Py文件),本质就是一个目录(必须带有一个__init__.py文件)