From 298e4214538a7196c27ec22b1f01506fdb3c4039 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 13 Feb 2003 16:30:16 +0000 Subject: SF patch #685738 by Michael Stone. This changes the default __new__ to refuse arguments iff tp_init is the default __init__ implementation -- thus making it a TypeError when you try to pass arguments to a constructor if the class doesn't override at least __init__ or __new__. --- Lib/copy_reg.py | 9 ++++++--- Lib/test/test_descr.py | 16 ++++++++-------- Misc/NEWS | 6 ++++++ Objects/typeobject.c | 20 +++++++++++++++++++- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Lib/copy_reg.py b/Lib/copy_reg.py index 11ae960..6dc52c2 100644 --- a/Lib/copy_reg.py +++ b/Lib/copy_reg.py @@ -33,11 +33,14 @@ def pickle_complex(c): pickle(type(1j), pickle_complex, complex) -# Support for picking new-style objects +# Support for pickling new-style objects def _reconstructor(cls, base, state): - obj = base.__new__(cls, state) - base.__init__(obj, state) + if base is object: + obj = object.__new__(cls) + else: + obj = base.__new__(cls, state) + base.__init__(obj, state) return obj _HEAPTYPE = 1<<9 diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 77bf61a..ffd86bc 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3694,8 +3694,8 @@ def subclass_right_op(): def __rdiv__(self, other): return "C.__rdiv__" - vereq(C(1) / 1, "C.__div__") - vereq(1 / C(1), "C.__rdiv__") + vereq(C() / 1, "C.__div__") + vereq(1 / C(), "C.__rdiv__") # Case 3: subclass of new-style class; here it gets interesting @@ -3705,8 +3705,8 @@ def subclass_right_op(): def __rdiv__(self, other): return "D.__rdiv__" - vereq(D(1) / C(1), "D.__div__") - vereq(C(1) / D(1), "D.__rdiv__") + vereq(D() / C(), "D.__div__") + vereq(C() / D(), "D.__rdiv__") # Case 4: this didn't work right in 2.2.2 and 2.3a1 @@ -3715,10 +3715,10 @@ def subclass_right_op(): vereq(E.__rdiv__, C.__rdiv__) - vereq(E(1) / 1, "C.__div__") - vereq(1 / E(1), "C.__rdiv__") - vereq(E(1) / C(1), "C.__div__") - vereq(C(1) / E(1), "C.__div__") # This one would fail + vereq(E() / 1, "C.__div__") + vereq(1 / E(), "C.__rdiv__") + vereq(E() / C(), "C.__div__") + vereq(C() / E(), "C.__div__") # This one would fail def dict_type_with_metaclass(): if verbose: diff --git a/Misc/NEWS b/Misc/NEWS index cfcb7ac..dc6f1db 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,12 @@ What's New in Python 2.3 alpha 2? Core and builtins ----------------- +- If a new-style class defines neither __new__ nor __init__, its + constructor would ignore all arguments. This is changed now: the + constructor refuses arguments in this case. This might break code + that worked under Python 2.2. The simplest fix is to add a no-op + __init__: "def __init__(self, *args, **kw): pass". + - Through a bytecode optimizer bug (and I bet you didn't even know Python *had* a bytecode optimizer :-), "unsigned" hex/oct constants with a leading minus sign would come out with the wrong sign. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7a8bcd9..eb2e08f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2251,6 +2251,24 @@ object_init(PyObject *self, PyObject *args, PyObject *kwds) return 0; } +/* If we don't have a tp_new for a new-style class, new will use this one. + Therefore this should take no arguments/keywords. However, this new may + also be inherited by objects that define a tp_init but no tp_new. These + objects WILL pass argumets to tp_new, because it gets the same args as + tp_init. So only allow arguments if we aren't using the default init, in + which case we expect init to handle argument parsing. */ +static PyObject * +object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + if (type->tp_init == object_init && (PyTuple_GET_SIZE(args) || + (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)))) { + PyErr_SetString(PyExc_TypeError, + "default __new__ takes no parameters"); + return NULL; + } + return type->tp_alloc(type, 0); +} + static void object_dealloc(PyObject *self) { @@ -2487,7 +2505,7 @@ PyTypeObject PyBaseObject_Type = { 0, /* tp_dictoffset */ object_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + object_new, /* tp_new */ PyObject_Del, /* tp_free */ }; -- cgit v0.12