接受JSON参数中的元组的Pythonic方式

3

我有一个脚本,它可以通过命令行接受参数来创建一个matplotlib.patches.Rectangle对象。

传递给Rectangle构造函数的典型参数可能是以下内容(在Python中,未经解析的参数):

patches.Rectangle(
    xy=(15000,0),
    width=9.4,
    height=4,
    color='peachpuff'
)

用户可以在命令行中这样编码:
--patches '[{ "x" : 15000,"y" : 0,"width" : 9.4,"height" : 4,"color" : "peachpuff"}]'

这个json数组使用json.loads进行加载。需要注意的是,大部分参数可以直接传递给Rectangle构造函数,但是xy元组会导致问题:由于json.loads永远不会生成元组类型,所以不能通过这种方式创建元组。
为了解决这个问题,我让用户传递单独的xy映射,然后像这样组合它们:
p.add_argument('--patches', help='A JSON array of patches.Rectangle object arguments to patch onto the chart',
    type=json.loads)

# stuff

# put some patches on
if args.patches:
    def from_json(json):
        ret = dict(json)
        del ret['x']
        del ret['y']
        ret['xy'] = (json['x'], json['y'])
        return ret
    for pjson in args.patches:
        p = from_json(pjson)
        ax.add_patch(patches.Rectangle(**p))

这段代码中有一半的内容(主要是 from_json 函数)都在处理将 xy 参数转换成元组 xy = (x, y)

有没有更加优雅/Pythonic的方式来处理呢?

可能涉及到更干净的 json 输入处理,或者在命令行上传递其他类型的参数(但必须与当前方法具有大致相同的功能)。


5
在 JSON 中,元组通常使用数组表示。您为什么不直接使用它呢?而且,它可能并不一定要是元组,只需要是具有 2 个值的可迭代对象即可。 - Jeff Mercado
2
优雅/Pythonic的方式是不必关心它是否特别是元组,正如@JeffMercado所评论的那样,而只是一些具有两个元素的序列。 - John Gordon
1
相关问题 - Lord Elrond
1
@JeffMercado - 我真是个白痴,我没想到Rectangle可以接受一个由2个元素组成的列表而不是元组,但它确实可以,没有问题。 - BeeOnRope
1
如果你真的想在脚本参数中使用Python字典语法,你也可以使用ast.literal_eval这种方式。 - modesitt
显示剩余4条评论
2个回答

4

你的from_json函数可以有效地用作自定义类型,适用于你的--patches选项。

def RectangleArgs(s):
    d = json.loads(s)
    d['xy'] = (d.pop('x'), d.pop('y'))
    return d


...

parser.add_argument('--patches', action='append', type=RectangleArgs)

...

for patch in args.patches:
    ax.add_patch(patches.Rectangle(**patch))

除了简单地对从命令行读取的JSON进行处理外,您还可以进行额外的验证,如果您发现在调用patches.Rectangle时返回值会引起问题,则会引发argparse.ArgumentTypeError


1
您的激励假设是错误的,您并不需要一个元组作为Rectangle函数的xy参数:一个包含两个元素的列表同样有效,因此"xy":"[1, 2]"将完美地工作。
在评论中由Jeff指出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接