summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2003-02-13 16:30:16 (GMT)
committerGuido van Rossum <guido@python.org>2003-02-13 16:30:16 (GMT)
commit298e4214538a7196c27ec22b1f01506fdb3c4039 (patch)
tree6d75d061df43965e30b132c378802c5488fd8f64
parent0c016a9590b3da47f19420d0616e0c72cae19abf (diff)
downloadcpython-298e4214538a7196c27ec22b1f01506fdb3c4039.zip
cpython-298e4214538a7196c27ec22b1f01506fdb3c4039.tar.gz
cpython-298e4214538a7196c27ec22b1f01506fdb3c4039.tar.bz2
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__.
-rw-r--r--Lib/copy_reg.py9
-rw-r--r--Lib/test/test_descr.py16
-rw-r--r--Misc/NEWS6
-rw-r--r--Objects/typeobject.c20
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 */
};