#偷梁换柱:即将原函数名指向的内存地址偷梁换柱成了wrapper函数,所以应该将wrapper做的跟原函数一样才行
from functools import wraps
def outer(func):
@wraps(func)
def wrapper(*args,**kwargs):
res = func(*args,**kwargs) #res=index(1,2)
return res
#将原函数的属性赋值给wrapper函数
#函数wrapper.__name__=原函数.__name__
#函数wrapper.__doc__=原函数.__doc__
#wrapper.__name__ =func.__name__
#wrapper.__doc__=func.__doc__
return wrapper
@outer #index=outer(index)
def index(x,y):
'''这个是主页功能'''
print(x,y)
print(index.__name__)
print(index.__doc__)
index(1,2) #wrapper(1,2)
一、知识储备
由于语法糖@的限制,outer函数只能有一个参数,并且该参数只用来接收被装饰对象的内存地址
def outer(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
@outer #index = outer(index) #index==>wrapper
def index(x,y):
print(x,y)
#偷梁换柱之后
#index的参数是什么样子,wrapper的参数就应该是什么样
#index的返回值什么样子,wrapper的返回值就应该是什么样子
#index的属性什么样子,wrapper的属性就应该是什么样子==>from functools import wraps
傻瓜1:
def auth(func,db_type):
def wrapper(*args,**kwargs):
name = input('your name:>>').strip()
pwd = input(your password:>>').strip()
if db_type == 'file':
#从文件中取账号密码进行验证
if name =='egon' and pwd == '123':
print('基于文件的验证')
res = func(*args,**kwargs)
return res
else:
print('user or password error')
elif db_type == 'mysql':
print('基于mysql的验证')
elif db_type == 'ldap':
print('基于ldap的验证')
else:
print('不支持db_type')
return wrapper
@auth #账号密码来源是文件
def index(x,y):
print('index->>%s:%s' %(x,y))
@auth #账号密码的来源是数据库
def home(name):
print('home->>%s' % name)
@auth #账号密码的来源是ldap
def transfer():
print('transfer')
index = auth(index,'file')
home = auth(home,'mysql')
transfer = auth(transfer,'ldap')
傻瓜2:
def auth(db_type):
def deco(func):
def wrapper(*args,**kwargs):
name = input('your name:>>').strip()
pwd = input('your password:>>').strip()
if db_type == 'file':
#从文件中取账号密码进行验证
if name == 'egon' and pwd == '123':
print('基于文件的验证')
res = func(*args,**kwargs)
return res
else:
print('user or password error')
elif db_type == 'mysql':
print('基于mysql的验证')
elif db_type == ‘ldap’:
print('基于ldap的验证')
else:
print('不支持db_type')
return wrapper
return deco
deco = auth(db_type = 'file')
@deco #账号密码来源是文件
def index(x,y):
print('index->>%s:%s' %(x,y))
deco = auth(db_type = 'mysql')
@deco #账号密码的来源是数据库
def home(name):
print(home-->%s' %name)
deco = auth(db_type = 'ldap')
@deco #账号密码的来源是ldap
def transfer():
print('transfer')
index(1,2)
home('egon')
transfer()
语法糖
def auth(db_type):
def deco(func):
def wrapper(*args,**kwargs):
name = input('your name>>:').strip()
pwd = input('your password>>:').strip()
if db_type == 'file':
#从文件中取账号密码进行验证
if name == 'egon' and pwd =='123':
print('基于文件的验证')
res = func(*args,**kwargs)
return res
else:
print('user or password error')
elif db_type == 'mysql':
print('基于mysql的验证')
elif db_type == 'ldap':
print('基于ldap的验证')
else:
print('不支持db_type')
return wrapper
return deco
@auth(db_type = 'file') #@dec0 #index = deco(index) #index=wrapper
def index(x,y):
print('index->>%s:%s' %s (x,y))
@auth(db_type = 'mysql') #账号密码的来源是数据库
def home(name):
print('home--> %s' %name)
@auth(db_type = 'ldap') #账号密码的来源是ldap
def transfer():
print('transfer')
index(1,2)
home('egon')
transfer()
有参装饰器模板
def 有参装饰器(x,y,z):
def outer(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
return outer
@有参装饰器(1, y =2 , z= 3)
def 被装饰对象():
pass
l = ['egon','liu','alex']
i = 0
while i < len(l):
print(l[i])
i+=1
上述迭代取值的方式只适用于有索引的数据类型:列表、字符串
为了解决基于索引迭代器取值的局限性,python必须提供一种能够不依赖索引的取值方式,这就是迭代器
3.如何用迭代器
s1 = ''
s1.__iter__()
l =[]
l.__iter__()
d = {
'a':1}
d.__iter__()
set1 ={
1,2,3}
set1.__iter__()
with open('a.txt',mode = 'w',encoding='utf-8') as f:
f.__iter__()
f.__next__()
调用可迭代对象下的__iter__方法会将其转换成迭代器对象
d = {
'a':1,'b':2,'c':3}
d_iterator = d.__iter__()
print(d_iterator)
print(d_iterator.__next__())
print(d_iterator.__next__())
print(d_iterator.__next__())
print(d_iterator.__next__()) # 抛出异常StopIteration 迭代器取值取干净了
l = [1,2,3,4,5]
l_iterator = l.__iter__()
while True:
try:
print(l_iterator.__next__())
except StopIteration:
break
4.可迭代对象与迭代器对象详解
可迭代对象(‘可以转换成迭代器的对象’):内置有__iter__方法对象
可迭代对象.iter():得到迭代器对象
可迭代对象:字符串、列表、元组、字典、集合、文件列表
迭代器对象:文件对象
s1 = ''
s1.__iter__()
l =[]
l.__iter__()
d = {
'a':1}
d.__iter__()
set1 ={
1,2,3}
set1.__iter__()
with open('a.txt',mode = 'w',encoding='utf-8') as f:
f.__iter__()
f.__next__()
迭代器:内置有__next__方法并且内置有__iter__方法的对象
迭代器对象.next():得到迭代器的下一个值
迭代器对象.iter():得到迭代器本身,说白了掉跟没调一样
dic = {
'a':1,'b':2}
dic_iterator = dic.__iter__()
print(dic_iterator is dic_iterator.__iter__())
for 循环的工作原理:for循环可以称之为迭代器循环
for x in 迭代器对象.__iter__():
d = {
'a':1,'b':2,'c':3}
d_iterator = d.__iter__()
while True:
try:
print(d_iterator.__next__())
except StopIteration:
break
d.iter() 得到一个迭代器对象
迭代器对象.next()拿到一个返回值,然后将该返回值赋值给k
循环往复上一步骤,直到抛出StopIteration异常 for循环会捕捉异常然后结束循环
for k in d:
print(k)
with open('笔记',mode = 'rt',encoding='utf-8') as fp:
for line in fp:
print(line)
list('hello') #原理同for循环
如何得到自定义的迭代器:
在函数内一旦存在yield关键字,调用函数并不会以执行函数体代码,会返回一个生成器对象,生成器即自定义的迭代器
def func():
print('first')
yield 1
print('second')
yield 2
print('third')
yield 3
print('fourth')
g = func()
print(g)
生成器就是迭代器
g.__iter__()
g.__next__()
会触发函数体代码的运行,然后遇到yield停下来,将yield后的值当做本次调用的结果返回
res1 = g.__next__()
print(res1)
res2 = g.__next__()
print(res2)
res3 = g.__next__()
print(res3)
res4 = g.__next__()
应用案例
def my_range(start,stop,step=1):
print('start...')
while start < stop:
start+=step
yield start
print('end...')
g = my_range(1,5,2)
print(next(g))
print(next(g))
print(next(g))