20

假设我定义了以下类:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

通常,可以通过以下方式之一实例化此类:

>>> MyClass(1,2)
<__main__.MyClass object at 0x8acbf8c>
>>> MyClass(1, y=2)
<__main__.MyClass object at 0x8acbeac>
>>> MyClass(x=1, y=2)
<__main__.MyClass object at 0x8acbf8c>
>>> MyClass(y=2, x=1)
<__main__.MyClass object at 0x8acbeac>

这很好,花花公子。

现在,我们尝试使用无效的关键字参数,看看会发生什么:

>>> MyClass(x=1, j=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'j'

Python 正确地引发类型错误并抱怨unexpected keyword argument 'j'.

现在,我们可以尝试使用两个无效的关键字参数:

>>> MyClass(i=1,j=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'i'

'i'请注意,其中两个关键字参数无效,但在这种情况下,Python 只抱怨其中一个。

让我们颠倒无效关键字参数的顺序:

>>> MyClass(j=2, i=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'i'

这太有趣了。我更改了无效关键字参数的顺序,但 Python 仍然决定抱怨'i'而不是'j'. 所以 Python 显然不会简单地选择第一个无效的键来抱怨。

让我们尝试更多:

>>> MyClass(c=2, i=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'i'
>>> MyClass(q=2, i=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'i'

按字母顺序,我尝试了一个字母 beforei和一个 after i,所以 Python 不会按字母顺序抱怨。

这里还有一些,这次是i在第一个位置:

>>> MyClass(i=1, j=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'i'
>>> MyClass(i=1, b=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'i'
>>> MyClass(i=1, a=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'a'

啊哈!我得到它来抱怨'a'而不是'i'

我的问题是,当给类构造函数提供无效的关键字参数时,Python 如何确定要抱怨哪一个?

4

1 回答 1

19

关键字参数存储在字典中,并且字典顺序(例如任意,基于散列算法、散列冲突和插入历史)适用。

对于您的第一个示例,同时包含ij键的字典i会首先列出:

>>> dict(j=2, i=1)
{'i': 1, 'j': 2}

请注意,{...}字面量 dict 表示法从右到左插入键,而关键字解析从左到右插入关键字(这是 CPython 实现细节);因此dict()在上面的例子中使用了构造函数。

当两个键散列到同一个插槽时,这很重要,例如ia

>>> dict(i=1, a=2)
{'a': 2, 'i': 1}
>>> {'i': 1, 'a': 2}
{'i': 1, 'a': 2}

字典输出顺序高度依赖于插入和删除历史以及具体的 Python 实现;例如, Python 3.3 引入了随机哈希种子来防止严重的拒绝服务向量,这意味着即使在 Python 进程之间,字典顺序也会完全不同。

于 2013-08-30T18:24:18.047 回答