我有以下代码在最终调用matplotlib的脚本中从命令行设置y和x轴限制(这里ax
是matplotlib axes
对象,但不应这样做)确实很重要,p
是一个ArgumentParser
实例):
p.add_argument('--ylim', help='Set the y axis limits explicitly (e.g., to cross at zero)', type=float, nargs='+')
p.add_argument('--xlim', help='Set the x axis limits explicitly', type=float, nargs='+')
# more stuff
if args.ylim:
if (len(args.ylim) == 1):
ax.set_ylim(args.ylim[0])
elif (len(args.ylim) == 2):
ax.set_ylim(args.ylim[0], args.ylim[1])
else:
sys.exit('provide one or two args to --ylim')
if args.xlim:
if (len(args.xlim) == 1):
ax.set_xlim(args.xlim[0])
elif (len(args.xlim) == 2):
ax.set_xlim(args.xlim[0], args.xlim[1])
else:
sys.exit('provide one or two args to --xlim')
如果您相信DRY可能会使您的眼睛发烫:这两个块是相同的,除了xlim
在第二个地方替换ylim
之外。
如何重构它以删除重复项?我曾两次调用某种限位设置功能似乎很明显,但是例如,如何传递我想在一种情况下调用set_ylim
而在另一种情况下调用set_xlim
的事实呢?
请注意,在未指定任何--*lim
参数的情况下调用脚本是完全有效的,并且应该表现为-如果从未调用过相应的set_*lim
函数(即,如上述代码中所示) -尽管调用了这些函数,但效果与示例一样好。
答案 0 :(得分:3)
函数是一流的对象。如果您在不调用ax.set_ylim
的情况下编写set_ylim()
函数,则会得到对ax
绑定的def check(name, lim, setter)
if not lim:
return
if (len(lim) == 1):
setter(lim[0])
elif (len(lim) == 2):
setter(lim[0], lim[1])
else:
sys.exit(f'provide one or two args to {name}')
check('--ylim', args.ylim, ax.set_ylim)
check('--xlim', args.xlim, ax.set_xlim)
函数的引用。
create table dbo.RealTable (RealColumn int not null);
go
create type dbo.TableOfNVarchar20 as table (Value nvarchar(20) not null);
go
create procedure dbo.usp_ProcReferencingMissingColumn
@tableOf20 dbo.TableOfNVarchar20 readonly
as
begin
set nocount on;
select top (1)
rt.MissingColumn
from dbo.RealTable rt
-- this join breaks all (column level) schema validation in Visual Studio
join @tableOf20 ou on ou.Value = rt.RealColumn
where rt.MissingColumn > getdate()
order by rt.MissingColumn desc;
end;
答案 1 :(得分:1)
有两个使用argparse的选项:
定义一个自定义操作,该操作将值的数量限制为指定范围,如Python argparse: Is there a way to specify a range in nargs?
这具有在传入参数的上下文中处理错误的优点;并且因为您的输入应该可以接受,所以您可以解压缩args。
# From: https://stackoverflow.com/a/4195302/3279716
def required_length(nmin,nmax):
class RequiredLength(argparse.Action):
def __call__(self, parser, args, values, option_string=None):
if not nmin<=len(values)<=nmax:
msg='argument "{f}" requires between {nmin} and {nmax} arguments'.format(
f=self.dest,nmin=nmin,nmax=nmax)
raise argparse.ArgumentTypeError(msg)
setattr(args, self.dest, values)
return RequiredLength
# Make parser
parser=argparse.ArgumentParser(prog='PROG')
parser.add_argument('--xlim', nargs='+', type=int, action=required_length(1,2))
parser.add_argument('--ylim', nargs='+', type=int, action=required_length(1,2))
# Use args in code
ax.set_xlim(*args.xlim)
ax.set_ylim(*args.ylim)
或者,您可以允许输入长度为一个或多个(nargs=“+”
)的输入,然后仅手动检查输入的长度并在需要时引发解析器错误:
# Make parser
parser=argparse.ArgumentParser(prog='PROG')
parser.add_argument('--xlim', nargs='+', type=int)
parser.add_argument('--ylim', nargs='+', type=int)
# Check args
if not 1 <= len(args.xlim) <= 2:
parser.error("xlim must have length 1 or 2")
if not 1 <= len(args.ylim) <= 2:
parser.error("ylim must have length 1 or 2")
# Use args in code
ax.set_xlim(*args.xlim)
ax.set_ylim(*args.ylim)