Python 3.4与2.7中的超级.__ new__上的TypeError

时间:2018-06-03 13:06:26

标签: python

在Python 3中,以下代码抛出TypeError,因为object()不带参数。在Python 2.7中,不会抛出任何错误。为什么2.7不是错误?

class A(object):

    def __new__(self, **kwargs):
        return super(A, self).__new__(self, **kwargs)

    def __init__(self, **kwargs):
        super(A, self).__init__(**kwargs)


A(x=3)

1 个答案:

答案 0 :(得分:2)

好吧,看起来有人决定在2.6中弃用,但直到介于2.7.9和3.6.4之间时才提出异常。

来自typeobject.c的

/* You may wonder why object.__new__() only complains about arguments
   when object.__init__() is not overridden, and vice versa.

   Consider the use cases:

   1. When neither is overridden, we want to hear complaints about
      excess (i.e., any) arguments, since their presence could
      indicate there's a bug.

   2. When defining an Immutable type, we are likely to override only
      __new__(), since __init__() is called too late to initialize an
      Immutable object.  Since __new__() defines the signature for the
      type, it would be a pain to have to override __init__() just to
      stop it from complaining about excess arguments.

   3. When defining a Mutable type, we are likely to override only
      __init__().  So here the converse reasoning applies: we don't
      want to have to override __new__() just to stop it from
      complaining.

   4. When __init__() is overridden, and the subclass __init__() calls
      object.__init__(), the latter should complain about excess
      arguments; ditto for __new__().

   Use cases 2 and 3 make it unattractive to unconditionally check for
   excess arguments.  The best solution that addresses all four use
   cases is as follows: __init__() complains about excess arguments
   unless __new__() is overridden and __init__() is not overridden
   (IOW, if __init__() is overridden or __new__() is not overridden);
   symmetrically, __new__() complains about excess arguments unless
   __init__() is overridden and __new__() is not overridden
   (IOW, if __new__() is overridden or __init__() is not overridden).

   However, for backwards compatibility, this breaks too much code.
   Therefore, in 2.6, we'll *warn* about excess arguments when both
   methods are overridden; for all other cases we'll use the above
   rules.
*/

2.7确实给出了警告(object_init中的类似代码):

static PyObject *
object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int err = 0;
    if (excess_args(args, kwds)) {
        if (type->tp_new != object_new &&
            type->tp_init != object_init)
        {
            err = PyErr_WarnEx(PyExc_DeprecationWarning,
                       "object() takes no parameters",
                       1);
        }
        else if (type->tp_new != object_new ||
                 type->tp_init == object_init)
        {
            PyErr_SetString(PyExc_TypeError,
                "object() takes no parameters");
            err = -1;
        }
    }
...
}

但是只有在python命令行上启用弃用警告(选项-Wd)时才会看到它。