Python-装饰器的应用(命令分发器)

写一个命令分发器

  • 程序员可以方便的注册函数到某一个命令,用户输入命令时,路由到注册的函数
  • 如果此命令没有对应的注册函数,执行默认函数
  • 用户输入用input(">>")

分析

  • 输入命令映射到一个函数,并执行这个函数。应该是cmd_tbl[cmd] = fn的形式,字典正好合适
  • 如果输入了某一个cmd命令后,没有找到函数,就要调用缺省的函数执行,这正好是字典缺省参数
  • cmd是字符串
# 构建全局字典
cmd_table = {}

# 注册函数
def reg(cmd, fn):
    cmd_table[cmd] = fn

# 缺省函数
def default_func():
    print('Unknown command')

# 分发器,调度
def dispatcher():
    while True:
        cmd = input(">>")
        # 退出条件
        if cmd.strip() == '':
            return
        cmd_table.get(cmd, default_func)() # get,当cmd不存在时,使用缺省值defaul_func

# 自定义函数
def foo1():
    print('hello')
def foo2():
    print('python')
    
# 注册
reg('hi', foo1)
reg('py', foo2)

# 循环
dispatcher()
  • 分析:
  1. 代码函数的注册不好看
  2. 所有的函数和字典都在全局中定义,不好
  • 改进办法

封装

  • 将reg函数封装成装饰器,并用它来注册函数
def command_dispatcher():
    # 构建全局字典
    cmd_table = {}

    # 注册函数
    def reg(cmd):
        def _reg(fn):
            cmd_table[cmd] = fn
            return fn

        return _reg
    # 缺省函数
    def default_func():
        print('Unknown command')

    # 分发器,调度
    def dispatcher():
        while True:
            cmd = input(">>")
            # 退出条件
            if cmd.strip() == '':
                return
            cmd_table.get(cmd, default_func)()
            # get,当cmd不存在时,使用缺省值defaul_func
    return reg,dispatcher # 把两个函数标识符(分别对应函数)封装到元组中

reg, dispatcher = command_dispatcher() # 将两个函数解构

# 自定义函数
@reg('hi')
def foo1():
    print('hello')

@reg('py')
def foo2():
    print('python')
    
# 循环
dispatcher()

完善命令分发器

  • 完善命令分发器,实现函数可以带任意参数(可变参数除外),解析参数并要求用户输入
  • 即解决下面的问题
# 自定义函数
@reg('hi')
def foo1(x,y):
	print('hello', x,  y)

@reg('py')
def foo2(a,=100):
	print('python', a, b)

思路

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

方式一实现

# 自定义函数可以有任意参数,可变参数、keyword-only除外
def command_dispatcher():
    # 构建全局字典
    cmd_tbl = {}

    # 注册函数
    def reg(cmd, *args, **kwargs):
        def _reg(fn):
            cmd_tbl[cmd] = fn, args, kwargs
            return fn
        return _reg
    # 缺省函数
    def default_func():
        print('Uknown command')

    # 调度器
    def dispatcher():
        while True:
            cmd = input('please input cmd>>')
            # 退出条件
            if cmd.strip() == '':
                return

            fn, args, kwargs = cmd_tbl.get(cmd, (default_func, (), {})) 
            # get,当cmd不存在时,使用缺省值(defaul_func, (), {}) ,并将其解构,fn对应default_func...
            fn(*args,**kwargs) # 调用cmd[0]或default_func函数

    return reg,dispatcher

reg, dispatcher = command_dispatcher()

# 自定义函数
@reg('hi', z=200, y=300, x=100)
@reg('hi1', z=300, y=300, x=300)
@reg('hi2', 1, 2, 3)
def foo1(x, y, z):
    print('hello',x, y, z)

@reg('py', 300, b=400)
def foo2(a, b=100):
    print('python', a, b)

# 调度循环
dispatcher()
```python
## 方法二实现

自定义函数可以有任意参数,可变参数、keyword-only除外

def command_dispatcher():
# 构建全局字典
commands = {}

# 注册函数
def reg(cmd):
	def _reg(fn):
    	commands[cmd] = fn
        return fn
    return _reg
# 缺省函数
def default_fn(*args,**kwargs):
	print('Uknown command')

# 调度器
def dispatcher():
	while True:
    cmd = input('>>')
    # 退出条件
    if cmd.strip() == '':
    	break
    else:
    	fname, *params = cmd.replace(',', ' ').split() #list
        #print(params) # ['1', 'y=5']
        args = []
        kwargs = {}
        for param in params:
        	x = param.split('=', maxsplit=1) # 按'='切,最大切一刀
                if len(x) == 1: # 顺序传参
                    args.append(int(x[0]))
                elif len(x) == 2: # a=1 [a,1]
                    kwargs[x[0]] = int(x[1])

            #print(args, kwargs)
            commands.get(fname, default_fn)(*args, **kwargs)
    return reg, dispatcher

reg, dispatcher = command_dispatcher()

# 自定义函数
@reg('hi')
def foo1(x, y):
    print('hello', x, y, x+y)

@reg('py')
def foo2(a, b=100):
    print('python', a, b, a+b)

# 调度循环
dispatcher()

# >> py 200 300
# >> py 200
# >> py 200,y=200
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值