Why Python’s function call semantics pass-in keyword arguments are not ordered?
利用函数定义中的双星语法,我们得到了一个规则字典。问题是,它松动了用户输入顺序。有时,我们可能想知道传递给函数的关键字参数的顺序。
因为函数调用通常不涉及很多参数,所以我不认为这是性能问题,所以我想知道为什么默认情况下不维护顺序。
我知道我们可以使用:
1 2 3 4 | from collections import Ordereddict def my_func(kwargs): print kwargs my_func(Ordereddict(a=1, b=42)) |
但它不如:
1 2 3 | def my_func(**kwargs): print kwargs my_func(a=1, b=42) |
[编辑1 ]:
1)我认为有两种情况:
- 我需要知道顺序,用户可以通过文档了解这种行为。
- 我不需要这个订单,所以我不在乎它是否被订购。
我没有想到,即使用户知道它使用命令,他也可以使用:
1 2 | a = dict(a=1, b=42) my_func(**a) |
因为他不知道听写是不受命令的(即使他应该知道)
2)我认为,在几个论点的情况下,开销不会很大,因此,有一个新的可能性来管理论点的好处将优于这个缺点。
但(从乔的回答来看)开销似乎不可忽略。
[编辑2 ]:
似乎PEP 0468——在一个函数中保持**kwargs的顺序,是朝着这个方向发展的。
因为字典不是按定义排序的。我觉得这真的很简单。
这是词典的定义。
CPython implementation detail: Keys and values are listed in an
arbitrary order which is non-random, varies across Python
implementations, and depends on the dictionary’s history of insertions
and deletions.
http://docs.python.org/2/library/stdtypes.html dict
python的字典是整个语言工作方式的核心,因此它们是高度优化的。添加排序将影响性能,并需要更多的存储和处理开销。
你可能会遇到一个不真实的情况,但我认为这比普通情况更为特殊。为一个非常热的代码路径添加一个"以防万一"的特性不是一个明智的设计决策。
编辑:
只是FYI
1 2 3 4 5 | >>> 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是标准库的一部分,所以我不认为有更多的性能可以从中挤出。
作为一个相反的论点,这里有一个这样做会导致复杂语义的例子。这里有几个案例:
- 函数总是得到一个无序的字典。
- 函数总是得到一个有序的字典-鉴于此,我们不知道顺序是否有任何意义,就像用户传递无序的数据结构一样,顺序是任意的,而数据类型则意味着顺序。
- 函数获取传入的内容——这看起来很理想,但并不那么简单。
关于
考虑到这一点,我会说对关键字参数进行排序是没有用的,因为不可能知道这个顺序是否只是一个任意的顺序。这会模糊函数调用的语义。
考虑到这一点,将其作为呼叫的一部分所获得的任何好处都将失去——相反,只需期待一个
检索通过**kwargs传递的关键字参数的顺序对于我正在进行的特定项目非常有用。它是关于制作一种具有有意义的尺寸的n-d numpy阵列(现在称为dimarray),特别适用于地球物理数据处理。
我在这里发布了一个有例子的问题:
如何检索传递给函数调用的关键字参数的原始顺序?
如果函数的参数是如此相关以至于名称和顺序都很重要,那么考虑使用特定的数据结构或定义一个类来保存它们。很有可能,您希望它们在代码的其他地方放在一起,并可能定义使用它们的其他函数/方法。