From 8ace1ab53a49d90d66e8a03491a272c70ad4eb46 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 6 Apr 2002 01:05:01 +0000 Subject: - Changed new-style class instantiation so that when C's __new__ method returns something that's not a C instance, its __init__ is not called. [SF bug #537450] --- Lib/test/test_descr.py | 22 ++++++++++++++++++++++ Misc/NEWS | 4 ++++ Objects/typeobject.c | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 8d8c276..ab55952 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -2897,6 +2897,27 @@ def dictproxyiteritems(): keys.sort() vereq(keys, ['__dict__', '__doc__', '__module__', '__weakref__', 'meth']) +def funnynew(): + if verbose: print "Testing __new__ returning something unexpected..." + class C(object): + def __new__(cls, arg): + if isinstance(arg, str): return [1, 2, 3] + elif isinstance(arg, int): return object.__new__(D) + else: return object.__new__(cls) + class D(C): + def __init__(self, arg): + self.foo = arg + vereq(C("1"), [1, 2, 3]) + vereq(D("1"), [1, 2, 3]) + d = D(None) + veris(d.foo, None) + d = C(1) + vereq(isinstance(d, D), True) + vereq(d.foo, 1) + d = D(1) + vereq(isinstance(d, D), True) + vereq(d.foo, 1) + def test_main(): class_docstrings() lists() @@ -2959,6 +2980,7 @@ def test_main(): dictproxyitervalues() dictproxyiteritems() pickleslots() + funnynew() if verbose: print "All OK" if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS index 8c42460..4923dce 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -6,6 +6,10 @@ Type/class unification and new-style classes Core and builtins +- Changed new-style class instantiation so that when C's __new__ + method returns something that's not a C instance, its __init__ is + not called. [SF bug #537450] + - Fixed super() to work correctly with class methods. [SF bug #535444] - A new built-in type, bool, has been added, as well as built-in diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 71d22f3..51ed430 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -169,6 +169,10 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) return obj; + /* If the returned object is not an instance of type, + it won't be initialized. */ + if (!PyType_IsSubtype(obj->ob_type, type)) + return obj; type = obj->ob_type; if (type->tp_init != NULL && type->tp_init(obj, args, kwds) < 0) { -- cgit v0.12