为什么Python的函数调用语义传入关键字参数不是有序的?

时间:2013-08-06 10:13:38

标签: python

使用函数定义中的双星语法,我们获得了一个常规字典。问题是它松开了用户输入顺序。有时,我们可能想知道传递给函数的关键字参数的顺序。

由于函数调用通常不涉及很多参数,我认为这不是性能问题所以我想知道为什么默认不是为了维护顺序。

我知道我们可以使用:

from collections import Ordereddict
def my_func(kwargs):
    print kwargs
my_func(Ordereddict(a=1, b=42))

但它不那么简洁:

def my_func(**kwargs):
    print kwargs
my_func(a=1, b=42)

[编辑1]:

1)我认为那里有2个案例:

  • 我需要知道顺序,用户可以通过文档了解此行为。
  • 我不需要订单,所以我不在乎是否订购。

我没想到即使用户知道它使用订单,他也可以使用:

a = dict(a=1, b=42)
my_func(**a)

因为他不知道没有下令(即使他应该知道)

2)我认为在一些论点的情况下开销不会很大,所以有一个新的可能性来管理论证的好处将优于这个缺点。

但似乎(来自Joe的回答)开销不可忽视。

[编辑2]:

似乎PEP 0468 -- Preserving the order of **kwargs in a function正朝这个方向发展。

4 个答案:

答案 0 :(得分:7)

因为字典不按定义排序。我觉得这很简单。 kwargs的要点是准确处理那些未订购的形式参数。如果您确实知道订单,那么您可以将其作为正常的'参数或*args

这是字典定义。

  

CPython实现细节:键和值列在   非随机的任意顺序因Python而异   实现,并取决于字典的插入历史   和删除。

http://docs.python.org/2/library/stdtypes.html#dict

Python的词典是整个语言工作方式的核心,因此它们经过高度优化。添加排序会影响性能并需要更多存储和处理开销。

你可能会遇到这样的情况,但我认为这种情况比普通情况更为特殊。添加功能'以防万一'对于非常热门的代码路径并不是一个明智的设计决策。

编辑:

仅供参考

>>> timeit.timeit(stmt="z = dict(x)", setup='x = ((("one", "two"), ("three", "four"), ("five", "six")))', number=1000000)
1.6569631099700928

>>> timeit.timeit(stmt="z = OrderedDict(x)", setup='from collections import OrderedDict; x = ((("one", "two"), ("three", "four"), ("five", "six")))', number=1000000)
31.618864059448242

在构建一个小小的正常情况下,速度差异大约为30倍。大小字典。 OrderedDict是标准库的一部分,因此我无法想象还有更多的性能可以从中挤出来。

答案 1 :(得分:3)

作为反驳论证,这里是一个复杂语义的例子。这里有几个案例:

  • 该函数始终会获得无序字典。
  • 该函数总是得到一个有序字典 - 鉴于此,我们不知道该顺序是否有任何意义,就好像用户传入无序数据结构,顺序将是任意的,而数据类型意味着顺序。
  • 该函数获取传入的内容 - 这看起来很理想,但并不是那么简单。

some_func(a=1, b=2, **unordered_dict)的案例怎么样?原始关键字参数中存在隐式排序,但是dict是无序的。订购与否之间没有明确的选择。

鉴于此,我会说排序关键字参数没有用,因为无法判断订单是否只是一个任意的。这会使函数调用的语义变得模糊。

鉴于此,将此作为调用的一部分所获得的任何好处都将丢失 - 相反,只需要OrderedDict作为参数。

答案 2 :(得分:0)

如果函数的参数关联到名称和顺序都很重要,请考虑使用特定的数据结构或定义一个类来保存它们。您可能希望它们在代码中的其他位置一起使用,并可能定义使用它们的其他功能/方法。

答案 3 :(得分:0)

检索通过** kwargs传递的关键字参数的顺序在我正在处理的特定项目中非常有用。它是关于制作一种具有有意义尺寸的n-d numpy数组(现在称为dimarray),对地球物理数据处理特别有用。

我已在此处发布了一个已开发的问题示例:

How to retrieve the original order of key-word arguments passed to a function call?