方案五:
import time
def index(): #index=被装饰对象index函数的内存地址
time.sleep(1)
print("from index")
def foo(func): #func=被装饰对象index函数的内存地址
def wrapper():
start = time.time()
func() #func=被装饰对象index函数的内存地址
stop = time.time()
print("run time is %s" % (stop - start))
return wrapper #丢出来wrapper的是wrapper的函数内存地址,不可以加括号
index = foo(index) #foo()这个时候就等于wrapper
print(index) #这时候index就是wrapper,已经不是上面的index了
index()
方案六:将wrapper伪装成被装饰的函数,那么应该装的尽可能像一点
import time
def index(x,y,z):
time.sleep(1)
print("from index",x,y,z)
def home(name):
time.sleep(2)
print("welcome %s to home page"% name)
return 123
def foo(func):
def wrapper(*args,**wkargs):
start = time.time()
res = func(*args, **wkargs)
stop = time.time()
print("run time is %s" % (stop - start))
return res
return wrapper
index = foo(index)
index(1,2,3)
home = foo(home)
res = home("nana")
print(res)
注意小点:
我们在运行完一个函数代码后,如果事先定义好了return返回值。那么在函数代码运行结束后,函数的返回值是一定会被丢出来的。
丢出来的返回值跟变量值一样,直接添加一个变量名,通过print就可以直接看到了。
装饰器语法糖:
方案六:将wrapper伪装成被装饰的函数,那么应该装的尽可能像一点
import time
from functools import wraps #这个是python自带写好的装饰器,导入wraps的模块,会把func自带所有的属性全部覆盖给wrapper(加不加都可以)
def foo(func):
@wraps(func)
def wrapper(*args,**wkargs):
start = time.time()
res = func(*args, **wkargs)
stop = time.time()
print("run time is %s" % (stop - start))
return res
return wrapper
@foo #index=off(index) #foo(被装饰对象index函数的内存地址)-->返回wrapper函数的内存地址-->index=wrapper函数的内存地址
def index():
"""...这是index内存地址..."""
time.sleep(1)
print("from index")
@foo #home = foo(home)
def home(name):
time.sleep(2)
print("welcome %s to home page"% name)
return 123
res = home("nana")
print(res)
res = index()
print(res)
print(index.__name__)
print(index.__doc__)
无参装饰器的模板
def outter(func):
def wrapper(*args,**wkargs):
res=func(*args,**kwargs)
return res
return wrapper
登陆认证装饰器
def outter(func):
def wrapper(*args, **kwargs):
name = input("username:").strip()
pwd = input("password:").strip()
if name == "nana" and pwd == "123":
res = func(*args, **kwargs)
return res
else :
print("账号密码错误")
return wrapper
@outter
def index():
print("index")
index() # index = outter(index)
叠加多个装饰器
def doco1(func1): #func1=wrapper2的内存地址
def wrapper1(*args, **kwargs):
print("===========wrapper1")
res1 = func1(*args, **kwargs)
print("end1")
return res1
return wrapper1
def doco2(func2): #func2=wrapper3的内存地址
def wrapper2(*args, **kwargs):
print("===========wrapper2")
res2 = func2(*args, **kwargs)
print("end2")
return res2
return wrapper2
def doco3(func3): #func3=被装饰的index的内存地址
def wrapper3(*args, **kwargs):
print("============wrapper3")
res3 = func3(*args, **kwargs)
print("end3")
return res3
return wrapper3
index=wrapper1的内存地址
@deco1 #deco1 (wrapper2的内存地址)->wrapper1的内存地址
@deco2 #deco2 (被装饰wrapper3的内存地址)->wrapper2的内存地址
@deco3 #dexo3 (被装饰的index的内存地址)->wrapper3的内存地址
def index():
print("index...")
index()
运行是自上而下运行,先运行wrapper1,在运行wrapper2,在运行wrapper3,最后运行index。
返回值是自下而上的,先打印end3,再end2,最后end1。
最后的运行结果:
===========wrapper1
===========wrapper2
============wrapper3
index...
end3
end2
end1
迭代器
什么是迭代器
迭代器指的是迭代取值的工具
什么是迭代
迭代就是一个重复的过程,但是每一次重复都是在上一次的基础之上进行的
nums=[111,222,333]
nums = "hello"
def get(l):
i = 0
while i < len(l):
print(l[i])
i += 1
get(nums)
为何要用迭代器
1.迭代器提供了一种不依赖于索引的,通用的取值方案
2.节省内存
如何用迭代器
可迭代的对象
1.内置有_iter_方法的都叫可迭代的对象
调用可迭代对象_iter_方法,返回的是它的迭代器
迭代器对象
1.内置有_next_方法
2.内置有_iter_方法
调用可迭代对象_iter_方法,得到的是它自己,就跟没调一样
调用迭代器_next_的方法返回的下一个值,不依赖索引
可以一直调用_next_直到取干净,则抛出异常StopIteration
迭代器对象包含了可迭代对象
内置的类型都是可迭代的对象
"abc"
[1, 2, 3]
(1, 2, 3)
{
"k1": 111}
{
1, 2, 3}
f=open("a.txt",mode="wt") #文件对象本身都是迭代器对象
nums = [1, 2, 3]
nums_iter = nums.__iter__()
print(nums)
print(nums_iter)
print(nums_iter.__next__())
print(nums_iter.__next__())
print(nums_iter.__next__())
print(nums_iter.__next__()) # 调完显示StopIteration
x = iter(nums) #将可迭代对像nums通过iter变成迭代器对象,赋值给x,x就变成了nums的迭代器
print(next(x))
print(next(x))
print(next(x))
for循环原理:
nums=[1,2,3]
nums=iter(nums) #将可迭代对象nums转成迭代器对象
try:
res = next(nums_iter)
print(res)
except StopIteration: # 捕捉异常结束
break
先调用in后那个对象_iter_方法,拿到迭代器对象
res=next(迭代器对象),执行一次循环体代码
循环往复步骤2:直到值取干净抛出异常StopIteration.for会捕捉异常结束循环
for res in nums:
print(res)
yield 与return的异同
相同点:返回值层面用法一样
不同点:return只能返回值一次,而yield的返回值可以返回多次
def func():
print("xxx")
yield 111
print("yyy")
yield 222
print("zzz")
yield 333
print("mmm")
g = func()
res=next(g)
print(res)
next(g)
next(g)
next(g)
next(g)
当函数内出现yield关键字,再调用函数并不会触发函数体代码的运行,会返回一个生成器
print(g) #生成器就是一种自定义的迭代器,yield可以将函数暂停住,next一次,会运行一次,当一个函数里面所有的yield全部取值干净了,会返回异常StopIteration