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
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341