在 **kwargs 中使用 OrderedDict [英] Using an OrderedDict in **kwargs

查看:72
本文介绍了在 **kwargs 中使用 OrderedDict的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以将 OrderedDict 实例传递给使用 **kwargs 语法并保留排序的函数?

我想做的是:

def I_crave_order(**kwargs):对于 kwargs.items() 中的 k, v:打印 k, v示例 = OrderedDict([('first', 1), ('second', 2), ('third', -1)])I_crave_order(**示例)>>第 1 个>>第二个2>>第三个-1

然而实际结果是:

<代码>>>第二个2>>第三个-1>>第 1 个

即典型的随机字典排序.

我还有其他用途,明确设置顺序很好,所以我想保留 **kwargs 而不仅仅是将 OrderedDict 作为常规参数传递

解决方案

从 Python 3.6 开始,保留关键字参数顺序.在 3.6 之前,这是不可能的,因为 OrderedDict 变成了 dict.

<小时>

首先要意识到的是,您在**example 中传递的值不会自动成为**kwargs 中的值.考虑这种情况,其中 kwargs 将只有 example 的一部分:

def f(a, **kwargs):经过示例 = {'a': 1, 'b': 2}f(**示例)

或者在这种情况下,它将具有比示例中更多的值:

example = {'b': 2}f(a=1, c=3, **示例)

甚至根本没有重叠:

example = {'a': 1}f(b=2, **例子)

<小时>

所以,你的要求没有任何意义.

不过,如果有某种方法来指定您想要一个有序的 **kwargs 可能会很好,无论关键字来自哪里——显式关键字参数按照它们出现的顺序,然后是 **example 的所有项目,按照它们在 example 中出现的顺序(如果 example 可以是任意的> 是一个 dict,但如果它是一个 OrderedDict,也可能是有意义的.

定义所有繁琐的细节并保持可接受的性能,结果证明比听起来更难.请参阅 PEP 468 和链接的线程,了解有关该想法的一些讨论.这一次它似乎停滞不前,但是如果有人拿起它并支持它(并编写一个参考实现供人们使用——这取决于可从 C API 访问的 OrderedDict,但是有望在 3.5+ 中出现),我怀疑它最终会进入该语言.

<小时>

顺便说一句,请注意,如果 可能的话,它几乎肯定会在 OrderedDict 本身的构造函数中使用.但是,如果您尝试这样做,您所做的就是将某些任意订单冻结为永久订单:

<预><代码>>>>d = OrderedDict(a=1, b=2, c=3)OrderedDict([('a', 1), ('c', 3), ('b', 2)])

<小时>

与此同时,您有哪些选择?

嗯,显而易见的选择就是将 example 作为普通参数传递,而不是解压它:

def f(示例):经过示例 = OrderedDict([('a', 1), ('b', 2)])f(示例)

或者,当然,您可以使用 *args 并将项目作为元组传递,但这通常更难看.

从 PEP 链接的线程中可能还有其他一些解决方法,但实际上,没有比这更好的了.(除了…… IIRC,李昊毅基于他的 MacroPy 提出了一个解决方案来传递保留订单的关键字参数,但我不记得细节了.如果您愿意使用 MacroPy 并编写读起来不像 Python 的代码,MacroPy 解决方案通常很棒,但这并不总是合适的......)

Is it possible to pass an OrderedDict instance to a function which uses the **kwargs syntax and retain the ordering?

What I'd like to do is :

def I_crave_order(**kwargs):
    for k, v in kwargs.items():
        print k, v

example = OrderedDict([('first', 1), ('second', 2), ('third', -1)])

I_crave_order(**example)
>> first 1
>> second 2
>> third -1

However the actual result is:

>> second 2
>> third -1
>> first 1

ie, typical random dict ordering.

I have other uses where setting the order explicitly is good, so I want to keep **kwargs and not just pass the OrderedDict as a regular argument

解决方案

As of Python 3.6, the keyword argument order is preserved. Before 3.6, it is not possible since the OrderedDict gets turned into a dict.


The first thing to realize is that the value you pass in **example does not automatically become the value in **kwargs. Consider this case, where kwargs will only have part of example:

def f(a, **kwargs):
    pass
example = {'a': 1, 'b': 2}
f(**example)

Or this case, where it will have more values than those in example:

example = {'b': 2}
f(a=1, c=3, **example)

Or even no overlap at all:

example = {'a': 1}
f(b=2, **example)


So, what you're asking for doesn't really make sense.

Still, it might be nice if there were some way to specify that you want an ordered **kwargs, no matter where the keywords came from—explicit keyword args in the order they appear, followed by all of the items of **example in the order they appear in example (which could be arbitrary if example were a dict, but could also be meaningful if it were an OrderedDict).

Defining all the fiddly details, and keeping the performance acceptable, turns out to be harder than it sounds. See PEP 468, and the linked threads, for some discussion on the idea. It seems to have stalled this time around, but if someone picks it up and champions it (and writes a reference implementation for people to play with—which depends on an OrderedDict accessible from the C API, but that will hopefully be there in 3.5+), I suspect it would eventually get into the language.


By the way, note that if this were possible, it would almost certainly be used in the constructor for OrderedDict itself. But if you try that, all you're doing is freezing some arbitrary order as the permanent order:

>>> d = OrderedDict(a=1, b=2, c=3)
OrderedDict([('a', 1), ('c', 3), ('b', 2)])


Meanwhile, what options do you have?

Well, the obvious option is just to pass example as a normal argument instead of unpacking it:

def f(example):
    pass
example = OrderedDict([('a', 1), ('b', 2)])
f(example)

Or, of course, you can use *args and pass the items as tuples, but that's generally uglier.

There might be some other workarounds in the threads linked from the PEP, but really, none of them are going to be better than this. (Except… IIRC, Li Haoyi came up with a solution based on his MacroPy to pass order-retaining keyword arguments, but I don't remember the details. MacroPy solutions in general are awesome if you're willing to use MacroPy and write code that doesn't quite read like Python, but that isn't always appropriate…)

这篇关于在 **kwargs 中使用 OrderedDict的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆