3.6 和 3.7 之间子类化的向后不兼容变化

Backwards incompat change in subclassing between 3.6 and 3.7

Python 3.6

>>> class Tup(tuple):
...     pass
... 
>>> Tup(x=123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'x' is an invalid keyword argument for this function

Python 3.7

>>> class Tup(tuple):
...     pass
... 
>>> Tup(x=123)
()

3.6 和 3.7 之间有什么变化?为什么?

较新版本 Python 中的行为是一个错误。

版本 3.6 和 3.7 之间的变化来自 tuple 处理其参数的方式。在 3.6 及更早版本中,tuple 的单个可选参数可以按位置(正常的、有记录的方式)传递,也可以作为关键字参数使用未记录的名称 sequence 作为参数传递。

>>> tuple(sequence="ab") # this only works on Python versions prior to 3.7
('a', 'b')

Python 3.7 删除了将参数作为关键字传递的功能。相反,它变成了一个仅限位置的论点。当时,只有内置函数可以有这种参数,尽管它们的语法记录在 PEP 457 (and they became available to normal Python code in Python 3.8 which implemented PEP 570) 中。您可以在 Python 的较新版本中的 tuple 文档中看到仅位置参数语法,其中参数的性质通过在构造函数签名中添加斜杠(在单个位置参数):

>>> help(tuple) # in more recent versions of Python
Help on class tuple in module builtins:

class tuple(object)
 |  tuple(iterable=(), /)
[...]

不幸的是,更改的实施似乎对 tuple 子类中关键字参数的处理产生了一些意想不到的后果,因为继承的构造函数方法默默地忽略了传递给它的所有关键字参数,而不是引发一个适当的例外(就像在 3.6 和之前对 sequence 以外的任何关键字名称所做的那样)。

此问题已报告给 Python 开发人员 bug tracking system(也许是您?)。一旦确定了解决问题的最佳方法,我希望它会针对仍在接受错误修复的 Python 版本进行修复(目前是 3.8 和 3.9,但不是仅获得安全修复的 3.7)。它可能需要几个月才能发布。