如何删除该参数处理代码的重复数据?

时间:2019-11-27 15:39:19

标签: python python-3.x refactoring argparse dry

我有以下代码在最终调用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函数(即,如上述代码中所示) -尽管调用了这些函数,但效果与示例一样好。

2 个答案:

答案 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)