Python装饰器练习 ---命令分发器的实现

装饰器的应用

一、写一个命令分发器

程序员可以方便的注册函数到某一个命令,用户输入命令时,路由到注册的函数
如果此命令没有对应的注册函数,执行默认函数,用户输入用input(">>")
分析:
输入命令映射到一个函数,并执行这个函数。(一直输入可以用while ) ,查找函数是否存在,字典正好合适。
如果输入了某一个cmd命令后,没有找到函数,就要调用缺省的函数执行,这正好是字典缺省参数。

commands = {}   #定义空字典
def reg (name,fn): # 用函数将定义的函数存在字典内
	commands[name] = fn
def default_func(): #默认函数
	print('unknown command')
def dispatcher():  # 调度函数
	while True:
		cmd = input('>>')
		if cmd.strip()=="":  #  删除空格 同时,如果用户输入的是空字符串这退出循环
			break
		commands.get(cmd,default_func)() # 存在则执行定义的函数,返回的是函数名所以要加以个括号 
def func1():
	print('func1')
def func2():
	print('func2')
reg('f1',func1)  #将函数存到字典中
reg('f2',func2)
dispatcher()# 调用主函数

上面写的是一个主初始的函数,虽然能够满足用户需求,但是,代码不够完美,而且所有的函数和字典都定义在全局变量中,不是最优选择.而且我们已经学过了柯里化与装饰器,可以进行进一步的优化.

装饰器封装

将reg函数封装成一个装饰器

commands = {}
def reg (name):   # 进行柯里化
	def wrapper(fn):
		commands[name] = fn
		return fn
	return wrapper
def default_func():
	print('unknown command')
def dispatcher():
	while True:
		cmd = input('>>')
		if cmd.strip()=="":  #  删除空格
			break
		commands.get(cmd,default_func)()
@reg('f1') #注册函数
def func1():
	print('func1')
@reg('f2')
def func2():
	print('func2')
dispatcher()

进一步把reg ,dispatcher 进行封装

def command_dispactcher():
	commands = {}
	def reg (name):
		def wrapper(fn):
			commands[name] = fn
			return fn
		return wrapper
	def default_func():
		print('unknown command')
	def dispatcher():
		while True:
			cmd = input('>>')
			if cmd.strip()=="":  #  删除空格
				break
			commands.get(cmd,default_func)()
	return  reg,dispatcher
reg ,dispatcher = command_dispactcher()  # 将函数command_dispactcher()的两个返回值进行解构 ,返回来的是一个元组
# 函数定义后就已经生效,并不会因为还没有调用,所以这里的解构是有可以的.
@reg('f1')
def func1():
	print('func1')
@reg('f2')
def func2():
	print('func2')
dispatcher()

穿插两个业务实际问题:
重复注册的问题
如果一个函数使用同样的cmd名称注册,就等于覆盖了原来的cmdfn的关系,这样的逻辑也是合理的。
也可以加一个判断,如果key已经存在,重复注册,抛出异常。看业务要求。
注销
有注册就应该有注销,从字典中移除。
一般来说注销是要有权限的,但是什么样的人拥有注销的权限,看业务要求。

二、完善命令分发器

完善命令分发器,实现函数可以带任意参数(可变参数除外),解析参数并要求用户输入
即解决下面的问题:

# 自定义函数
@reg('f1')
def func1(x,y):
print('f2', x, y)
@reg('py')
def func2(a,b=100):
print('func2', a, b)

思路:
可以有2种方式
1、注册的时候,固定死,@reg(‘py’,200,100)
可以认为@reg(‘py’,200,100)和@reg(‘py’,300,100)是不同的函数,可以用partial函数。
2、运行时,在输入cmd的时候,逗号或空格分割,获取参数。
至于函数的验证,以后实现。
一般用户都喜欢使用单纯一个命令如mag,然后直接显示想要的结果,就采用方式一实现

方法一:

def command_dispactcher():
	commands = {}
	def reg (name,*args,**kwargs): # 接收多个传参 
		def wrapper(fn):
			commands[name] = fn,args,kwargs  #字典收集起来的values是一个元组
			# x3=> func1,(),{x:1,y:2}
			# x2 => func1,(100,200),{}
			# x1 => func1,(200,300),{}
			return fn
		return wrapper
	def default_func(*args,**kwargs):
		print('unknown command')
	def dispatcher():
		while True:
			cmd = input('>>')
			if cmd.strip()=="": 
				break
             commands.get(cmd,(default_func)# 这是未完善时缺省值的定义
             #现在字典的values返回的值是一个元组,有三个参数,所以这里返回的cmd也是三个参数.后面的缺省值也必须配三个元素,不然参数个数不匹配,会报错.
			fn,args,kwargs= commands.get(cmd,(default_func,(),{})) # 缺省值调用
			fn(*args,**kwargs)#上面得得到函数名,这里调用函数需要先进行解构.如参数错误则是定义的fn函数问题,与主程序无关.
	return  reg,dispatcher
reg ,dispatcher = command_dispactcher()  # 将command_dispactcher() 的返回值进行解构.
@reg('x1',200,300)  # func1  = reg(fn)(wrapper)
@reg('x2',100,200)
@reg('x3',x=1,y=2)
def func1(x,y):
	print('func1',x,y,x+y)
dispatcher()

如果用户输入的是:

>>f2 100,200

>>f2, 200,300

扫描二维码关注公众号,回复: 6133149 查看本文章

>>f2 200 300

这样的又该如何处理?

方法二:

def command_dispactcher():
	commands = {}
	def reg (name):
		def wrapper(fn):
			commands[name] = fn
			# x3=> func1,(),{x:1,y:2}
			# x2 => func1,(100,200),{}
			# x1 => func1,(200,300),{}
			return fn
		return wrapper
	def default_func(*args,**kwargs):
		print('unknown command')
	def dispatcher():
		while True:
			cmd = input('>>')
			if cmd.strip()=="":  #  删除空格
				return
			fnname,*params = cmd.replace(',',' ').split()# 处理输入字符,并进行解构
            # 解构的params是一个列表
			args=[]
			kwargs = {}
			for param in params:
				x = param.split('=',maxsplit = 1) 
				if len(x)==1: # 如果实单独的arg形式的参数,split之后长度是为1的,
					args.append(int(x[0]))# 加入到args里
				elif len(x )==2:# 如果分割长度等于了2,说明传参值肯定是关键字传参.
					kwargs[x[0]]=int(x[1]) # 加入到关键字传参里
			commands.get(fnname,default_func)(*args,**kwargs) # 函数名和参数的解构调用.
	return reg,dispatcher
reg ,dispatcher = command_dispactcher()  # 参数解构
@reg('f1')
def func1(a=100,b=200)
	print('func',a,b,a+b)
@reg('f2')
def func2(a,b=100):
	print('func2',a,b,a+b)
dispatcher()

猜你喜欢

转载自blog.csdn.net/qq_40498551/article/details/89608105