Python 异常处理

2023-01-31 01:01:04 python 异常

写一个命令分发器
初步要求 :

程序员可以方便地注册函数到某一个命令, 用户输入命令时, 路由到注册的函数, 如果此命令没有对应的函数, 执行默认函数
分析 :

输入命令映射到一个函数, 并执行这个函数, 应该是cmd_tbl[cmd] = fn 的形式, 使用字典比较合适
如果输入某一cmd 命令后, 没有找到函数就调用缺省的函数执行, 正好是字典的缺省参数, cmd 是字符串
基础框架 :

cmd_table = {}

def reg(cmd, fn):
cmd_table[cmd] = fn

def default_fun():
print('Unknow command')

def dispatcher():
while True:
cmd =input('>>')

    if cmd.strip() == '':   
        return 
    cmd_table.get(cmd, default_fun)()

def foo1():
print('text')
def foo2():
print('python')

reg('x', foo1)
reg('pyt', foo2)

dispatcher()
存在问题 :

函数注册太难看
函数和字典都在全局定义
如何在此基础上改进…

封装
将reg函数封装成装饰器, 并用它来注册函数

def reg(cmd):
def _reg(fn):
cmd_table[cmd] = fn
return fn
return _reg

@reg('x')
def foo1():
print('text') br/>@reg('pyt')
def foo2():
print('Python')
能否把字典, reg, dispatcher等也封装起来呢, 外面在使用的时候调度就可以了

def command_dispatcher():

cmd_table = {}

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

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

# 分发器, 调度
def dispatcher():
    while True:
        cmd = input('>>')
        # 退出条件
        if cmd.strip() == '':
            return 
        cmd_table.get(cmd, default_func)()
return reg, dispatcher
# 返回内层函数, 解构后外部调用

reg, dispatcher = command_dispatcher()

@reg('x')
def foo1():br/>print('text')
@reg('pyt')
def foo2():
print('python')

dispatcher()
输出结果 :

abcdef
Unknow command
x
text
pyt
python

符合设计预期 : 输入的cmd不存在的调用缺省函数, cmd存在则调用相应函数, 输入空格则退出
问题
重复注册

如果一个函数使用同样的cmd名注册, 就等于覆盖原有cmd到fn之间的关系, 这样的判断也是合理的, 不过也可以加一个判断, 如果key 已存在, 重复注册抛出异常, 具体情况具体分析
注销

有注册就应该有注销, 从字典中移除.
一般来说注销是有条件的, 什么人拥有注销权限看业务需求
完善命令分发器
实现函数可以带任意参数(可变参数除外), 解析参数并要求用户输入
即实现下面的问题 :

@reg('x')
def foo1(x, y):
print('text', x, y)br/>@reg('pyt')
def foo2(a, b=100):
print('python', a, b)
基本思路 :

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

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(*args, **kwargs):
    print('Unknow command')

# 调度器
def dispatcher():
    while True:
        cmd = input('Please input cmd >>')

        # 退出条件
        if cmd.strip() == '':
            return

        fn, args, kwargs = cmd_tbl.get(cmd, (default_func, (), {}))
        fn(*args, kwargs)
return reg, dispatcher

reg, dispatcher = command_dispatcher()

@reg('x1', z=200, y=300, x=100)
@reg('x2', z=300, y=300, x=300)
@reg('x3', 1, 2, 3)
def foo1(x, y, z):
print('text', x, y, z)

dispatcher()
输出结果 :

Please input cmd >> x1
text 100 300 200
Please input cmd >> x2
text 300 300 300
Please input cmd >> x3
text 1 2 3
Please input cmd >>
方法二 :

def command_dispatcher():
command = {}
def reg(cmd):
def _reg(fn):
command[cmd] = fn
return fn
return _reg
def default_fn(*args, kwargs):
print('Unknow command')
def dispatcher():
while True:
cmd = input('Please input cmd >>')
if cmd.strip() == '':
break
else:
fname, params = cmd.replace(',', ' ').split()
args = []
kwargs = {}
for param in params:
lis_param = param.split('=', maxsplit=1)
if len(lis_param) == 1:
args.append(lis_param[0])
elif len(lis_param) == 2:
kwargs[lis_param[0]] = lis_param[1]
command.get(fname, default_fn)(
args,
kwargs)
return reg, dispatcher
reg, dispatcher = command_dispatcher()

@reg('x')
def foo1(x, y):
print('text', x, y)

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

dispatcher()

输出结果 :

Please input cmd >> x 1 2
text 1 2
Please input cmd >> x x=1,y=4
text 1 4
Please input cmd >> pyt 5
python 5 100
Please input cmd >> pyt 4 8
python 4 8


相关文章