python之有参装饰器

装饰器

  • 装饰器补充
  • 有参装饰器
  • 迭代器
  • 生成器

装饰器补充

#偷梁换柱:即将原函数名指向的内存地址偷梁换柱成了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

迭代器

  1. 什么是迭代求
    迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的,单纯的重复并不是迭代。
    2.为何要有迭代
    迭代器是用来取值的工具,而涉及到把多个值循环取出来的类型有:
    列表、字符串、元组、自ID以、集合、打开文件
 l = ['egon','liu','alex']
 i = 0 
 while i < len(l):
 	print(l[i])
 	i+=1
上述迭代取值的方式只适用于有索引的数据类型:列表、字符串
为了解决基于索引迭代器取值的局限性,python必须提供一种能够不依赖索引的取值方式,这就是迭代器

3.如何用迭代器

  • 可迭代对象:但凡内置有__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__()

调用可迭代对象下的__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))

你可能感兴趣的:(python入门)