From ff737954f3ee3005236133fc51b55a508b11aa06 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 27 Nov 2007 10:40:20 +0000 Subject: [PATCH] Removed the API to create unbound methods and simplified the API for bound methods. The signature is PyMethod_New(func, instance). Also removed im_class and renamed im_self to __self__ and im_func to __func__. im_class can be substituted with method.__self__.__class__. I've also updated some parts of the documenation. --- Doc/library/inspect.rst | 9 +- Doc/library/new.rst | 6 +- Doc/library/stdtypes.rst | 14 +-- Doc/reference/datamodel.rst | 55 ++++----- Doc/tutorial/classes.rst | 4 +- Include/classobject.h | 9 +- Lib/ctypes/test/test_callbacks.py | 8 +- Lib/dis.py | 4 +- Lib/doctest.py | 4 +- Lib/idlelib/CallTips.py | 6 +- Lib/inspect.py | 13 +-- Lib/lib-tk/Tkinter.py | 2 +- Lib/pdb.py | 6 +- Lib/pydoc.py | 16 +-- Lib/test/crashers/borrowed_ref_2.py | 2 +- Lib/test/test_descr.py | 31 ++--- Lib/test/test_funcattrs.py | 41 +++---- Lib/test/test_new.py | 4 +- Lib/test/test_profilehooks.py | 2 +- Lib/test/test_pyclbr.py | 2 +- Misc/NEWS | 6 + Objects/classobject.c | 171 ++++++---------------------- Objects/funcobject.c | 5 +- 23 files changed, 152 insertions(+), 268 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index cf14de97202..988b73775e9 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -49,14 +49,11 @@ attributes: | | __name__ | name with which this | | | | method was defined | +-----------+-----------------+---------------------------+ -| | im_class | class object that asked | -| | | for this method | -+-----------+-----------------+---------------------------+ -| | im_func | function object | +| | __func__ | function object | | | | containing implementation | | | | of method | +-----------+-----------------+---------------------------+ -| | im_self | instance to which this | +| | __self__ | instance to which this | | | | method is bound, or | | | | ``None`` | +-----------+-----------------+---------------------------+ @@ -264,7 +261,7 @@ attributes: Methods implemented via descriptors that also pass one of the other tests return false from the :func:`ismethoddescriptor` test, simply because the other tests promise more -- you can, e.g., count on having the - :attr:`im_func` attribute (etc) when an object passes :func:`ismethod`. + :attr:`__func__` attribute (etc) when an object passes :func:`ismethod`. .. function:: isdatadescriptor(object) diff --git a/Doc/library/new.rst b/Doc/library/new.rst index 6153ff148bc..6c5a4bf8176 100644 --- a/Doc/library/new.rst +++ b/Doc/library/new.rst @@ -17,10 +17,10 @@ non-sensical arguments which crash the interpreter when the object is used. The :mod:`new` module defines the following functions: -.. function:: instancemethod(function, instance, class) +.. function:: instancemethod(function, instance) - This function will return a method object, bound to *instance*, or unbound if - *instance* is ``None``. *function* must be callable. + This function will return a method object, bound to *instance*. + *function* must be callable. .. function:: function(code, globals[, name[, argdefs[, closure]]]) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index e6f7e7b52ad..1e81ed935f9 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2216,21 +2216,21 @@ instance methods. Built-in methods are described with the types that support them. The implementation adds two special read-only attributes to class instance -methods: ``m.im_self`` is the object on which the method operates, and -``m.im_func`` is the function implementing the method. Calling ``m(arg-1, -arg-2, ..., arg-n)`` is completely equivalent to calling ``m.im_func(m.im_self, -arg-1, arg-2, ..., arg-n)``. +methods: ``m.__self__`` is the object on which the method operates, and +``m.__func__`` is the function implementing the method. Calling ``m(arg-1, +arg-2, ..., arg-n)`` is completely equivalent to calling ``m.__func__( +m.__self__, arg-1, arg-2, ..., arg-n)``. Class instance methods are either *bound* or *unbound*, referring to whether the method was accessed through an instance or a class, respectively. When a method -is unbound, its ``im_self`` attribute will be ``None`` and if called, an +is unbound, its ``__self__`` attribute will be ``None`` and if called, an explicit ``self`` object must be passed as the first argument. In this case, ``self`` must be an instance of the unbound method's class (or a subclass of that class), otherwise a :exc:`TypeError` is raised. Like function objects, methods objects support getting arbitrary attributes. However, since method attributes are actually stored on the underlying function -object (``meth.im_func``), setting method attributes on either bound or unbound +object (``meth.__func__``), setting method attributes on either bound or unbound methods is disallowed. Attempting to set a method attribute results in a :exc:`TypeError` being raised. In order to set a method attribute, you need to explicitly set it on the underlying function object:: @@ -2240,7 +2240,7 @@ explicitly set it on the underlying function object:: pass c = C() - c.method.im_func.whoami = 'my name is c' + c.method.__func__.whoami = 'my name is c' See :ref:`types` for more information. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 1e85f8305e1..75cb52f5d3e 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -538,20 +538,18 @@ Callable types A user-defined method object combines a class, a class instance (or ``None``) and any callable object (normally a user-defined function). - Special read-only attributes: :attr:`im_self` is the class instance object, - :attr:`im_func` is the function object; :attr:`im_class` is the class of - :attr:`im_self` for bound methods or the class that asked for the method for - unbound methods; :attr:`__doc__` is the method's documentation (same as - ``im_func.__doc__``); :attr:`__name__` is the method name (same as - ``im_func.__name__``); :attr:`__module__` is the name of the module the method - was defined in, or ``None`` if unavailable. + Special read-only attributes: :attr:`__self__` is the class instance object, + :attr:`__func__` is the function object; :attr:`__doc__` is the method's + documentation (same as ``__func__.__doc__``); :attr:`__name__` is the + method name (same as ``__func__.__name__``); :attr:`__module__` is the + name of the module the method was defined in, or ``None`` if unavailable. .. index:: single: __doc__ (method attribute) single: __name__ (method attribute) single: __module__ (method attribute) - single: im_func (method attribute) - single: im_self (method attribute) + single: __func__ (method attribute) + single: __self__ (method attribute) Methods also support accessing (but not setting) the arbitrary function attributes on the underlying function object. @@ -565,49 +563,46 @@ Callable types the original method object is used as it is. .. index:: - single: im_class (method attribute) - single: im_func (method attribute) - single: im_self (method attribute) + single: __func__ (method attribute) + single: __self__ (method attribute) When a user-defined method object is created by retrieving a user-defined - function object from a class, its :attr:`im_self` attribute is ``None`` + function object from a class, its :attr:`__self__` attribute is ``None`` and the method object is said to be unbound. When one is created by retrieving a user-defined function object from a class via one of its - instances, its :attr:`im_self` attribute is the instance, and the method - object is said to be bound. In either case, the new method's - :attr:`im_class` attribute is the class from which the retrieval takes - place, and its :attr:`im_func` attribute is the original function object. + instances, its :attr:`__self__` attribute is the instance, and the method + object is said to be bound. Its :attr:`__func__` attribute is the + original function object. - .. index:: single: im_func (method attribute) + .. index:: single: __func__ (method attribute) When a user-defined method object is created by retrieving another method object from a class or instance, the behaviour is the same as for a function object, - except that the :attr:`im_func` attribute of the new instance is not the - original method object but its :attr:`im_func` attribute. + except that the :attr:`__func__` attribute of the new instance is not the + original method object but its :attr:`__func__` attribute. .. index:: - single: im_class (method attribute) - single: im_func (method attribute) - single: im_self (method attribute) + single: __func__ (method attribute) + single: __self__ (method attribute) When a user-defined method object is created by retrieving a class method object - from a class or instance, its :attr:`im_self` attribute is the class itself (the - same as the :attr:`im_class` attribute), and its :attr:`im_func` attribute is + from a class or instance, its :attr:`__self__` attribute is the class itself (the + same as the :attr:`im_class` attribute), and its :attr:`__func__` attribute is the function object underlying the class method. When an unbound user-defined method object is called, the underlying function - (:attr:`im_func`) is called, with the restriction that the first argument must + (:attr:`__func__`) is called, with the restriction that the first argument must be an instance of the proper class (:attr:`im_class`) or of a derived class thereof. When a bound user-defined method object is called, the underlying function - (:attr:`im_func`) is called, inserting the class instance (:attr:`im_self`) in + (:attr:`__func__`) is called, inserting the class instance (:attr:`__self__`) in front of the argument list. For instance, when :class:`C` is a class which contains a definition for a function :meth:`f`, and ``x`` is an instance of :class:`C`, calling ``x.f(1)`` is equivalent to calling ``C.f(x, 1)``. When a user-defined method object is derived from a class method object, the - "class instance" stored in :attr:`im_self` will actually be the class itself, so + "class instance" stored in :attr:`__self__` will actually be the class itself, so that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is the underlying function. @@ -741,7 +736,7 @@ Custom classes transformed into an unbound user-defined method object whose :attr:`im_class` attribute is :class:`C`. When it would yield a class method object, it is transformed into a bound user-defined method object whose :attr:`im_class` - and :attr:`im_self` attributes are both :class:`C`. When it would yield a + and :attr:`__self__` attributes are both :class:`C`. When it would yield a static method object, it is transformed into the object wrapped by the static method object. See section :ref:`descriptors` for another way in which attributes retrieved from a class may differ from those actually contained in @@ -786,7 +781,7 @@ Class instances is the class (call it :class:`C`) of the instance for which the attribute reference was initiated or one of its bases, it is transformed into a bound user-defined method object whose :attr:`im_class` attribute is :class:`C` and - whose :attr:`im_self` attribute is the instance. Static method and class method + whose :attr:`__self__` attribute is the instance. Static method and class method objects are also transformed, as if they had been retrieved from class :class:`C`; see above under "Classes". See section :ref:`descriptors` for another way in which attributes of a class retrieved via its instances may diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index ef6498e885e..4e954195a07 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -576,8 +576,8 @@ data from a string buffer instead, and pass it as an argument. .. % \code{sys.stdin} will not cause the interpreter to read further input .. % from it.) -Instance method objects have attributes, too: ``m.im_self`` is the instance -object with the method :meth:`m`, and ``m.im_func`` is the function object +Instance method objects have attributes, too: ``m.__self__`` is the instance +object with the method :meth:`m`, and ``m.__func__`` is the function object corresponding to the method. diff --git a/Include/classobject.h b/Include/classobject.h index 885c43e4cfd..e6ca421a5be 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -1,4 +1,4 @@ -/* Former class object interface -- now only (un)bound methods are here */ +/* Former class object interface -- now only bound methods are here */ /* Revealing some structures (not for general use) */ @@ -11,8 +11,7 @@ extern "C" { typedef struct { PyObject_HEAD PyObject *im_func; /* The callable object implementing the method */ - PyObject *im_self; /* The instance it is bound to, or NULL */ - PyObject *im_class; /* The class that asked for the method */ + PyObject *im_self; /* The instance it is bound to */ PyObject *im_weakreflist; /* List of weak references */ } PyMethodObject; @@ -20,7 +19,7 @@ PyAPI_DATA(PyTypeObject) PyMethod_Type; #define PyMethod_Check(op) ((op)->ob_type == &PyMethod_Type) -PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *); PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); @@ -32,8 +31,6 @@ PyAPI_FUNC(PyObject *) PyMethod_Class(PyObject *); (((PyMethodObject *)meth) -> im_func) #define PyMethod_GET_SELF(meth) \ (((PyMethodObject *)meth) -> im_self) -#define PyMethod_GET_CLASS(meth) \ - (((PyMethodObject *)meth) -> im_class) #ifdef __cplusplus } diff --git a/Lib/ctypes/test/test_callbacks.py b/Lib/ctypes/test/test_callbacks.py index d870eb424c4..bf580ae8bd8 100644 --- a/Lib/ctypes/test/test_callbacks.py +++ b/Lib/ctypes/test/test_callbacks.py @@ -14,7 +14,7 @@ class Callbacks(unittest.TestCase): return args[-1] def check_type(self, typ, arg): - PROTO = self.functype.im_func(typ, typ) + PROTO = self.functype.__func__(typ, typ) result = PROTO(self.callback)(arg) if typ == c_float: self.failUnlessAlmostEqual(result, arg, places=5) @@ -22,7 +22,7 @@ class Callbacks(unittest.TestCase): self.failUnlessEqual(self.got_args, (arg,)) self.failUnlessEqual(result, arg) - PROTO = self.functype.im_func(typ, c_byte, typ) + PROTO = self.functype.__func__(typ, c_byte, typ) result = PROTO(self.callback)(-3, arg) if typ == c_float: self.failUnlessAlmostEqual(result, arg, places=5) @@ -110,12 +110,12 @@ class Callbacks(unittest.TestCase): # functions, the type must have a non-NULL stgdict->setfunc. # POINTER(c_double), for example, is not supported. - prototype = self.functype.im_func(POINTER(c_double)) + prototype = self.functype.__func__(POINTER(c_double)) # The type is checked when the prototype is called self.assertRaises(TypeError, prototype, lambda: None) def test_unsupported_restype_2(self): - prototype = self.functype.im_func(object) + prototype = self.functype.__func__(object) self.assertRaises(TypeError, prototype, lambda: None) try: diff --git a/Lib/dis.py b/Lib/dis.py index 4cf452a097a..6d52694a75d 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -18,8 +18,8 @@ def dis(x=None): if x is None: distb() return - if hasattr(x, 'im_func'): - x = x.im_func + if hasattr(x, '__func__'): + x = x.__func__ if hasattr(x, '__code__'): x = x.__code__ if hasattr(x, '__dict__'): diff --git a/Lib/doctest.py b/Lib/doctest.py index 5b1807301af..f1350272480 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -913,7 +913,7 @@ class DocTestFinder: if isinstance(val, staticmethod): val = getattr(obj, valname) if isinstance(val, classmethod): - val = getattr(obj, valname).im_func + val = getattr(obj, valname).__func__ # Recurse to methods, properties, and nested classes. if ((inspect.isfunction(val) or inspect.isclass(val) or @@ -985,7 +985,7 @@ class DocTestFinder: break # Find the line number for functions & methods. - if inspect.ismethod(obj): obj = obj.im_func + if inspect.ismethod(obj): obj = obj.__func__ if inspect.isfunction(obj): obj = obj.__code__ if inspect.istraceback(obj): obj = obj.tb_frame if inspect.isframe(obj): obj = obj.f_code diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py index aee7e612871..cda2be979d2 100644 --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -116,7 +116,7 @@ class CallTips: def _find_constructor(class_ob): "Find the nearest __init__() in the class tree." try: - return class_ob.__init__.im_func + return class_ob.__init__.__func__ except AttributeError: for base in class_ob.__bases__: init = _find_constructor(base) @@ -133,7 +133,7 @@ def get_argspec(ob): if fob is None: fob = lambda: None elif isinstance(ob, types.MethodType): - fob = ob.im_func + fob = ob.__func__ else: fob = ob if isinstance(fob, (types.FunctionType, types.LambdaType)): @@ -183,7 +183,7 @@ def main(): name = t.__name__ # exercise fetch_tip(), not just get_argspec() try: - qualified_name = "%s.%s" % (t.im_class.__name__, name) + qualified_name = "%s.%s" % (t.__self__.__class__.__name__, name) except AttributeError: qualified_name = name argspec = ct.fetch_tip(qualified_name) diff --git a/Lib/inspect.py b/Lib/inspect.py index 3a95796792f..a1910e4ff96 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -55,9 +55,8 @@ def ismethod(object): Instance method objects provide these attributes: __doc__ documentation string __name__ name with which this method was defined - im_class class object in which this method belongs - im_func function object containing implementation of method - im_self instance to which this method is bound""" + __func__ function object containing implementation of method + __self__ instance to which this method is bound""" return isinstance(object, types.MethodType) def ismethoddescriptor(object): @@ -73,7 +72,7 @@ def ismethoddescriptor(object): Methods implemented via descriptors that also pass one of the other tests return false from the ismethoddescriptor() test, simply because the other tests promise more -- you can, e.g., count on having the - im_func attribute (etc) when an object passes ismethod().""" + __func__ attribute (etc) when an object passes ismethod().""" return (hasattr(object, "__get__") and not hasattr(object, "__set__") # else it's a data descriptor and not ismethod(object) # mutual exclusion @@ -351,7 +350,7 @@ def getfile(object): return object.__file__ raise TypeError('arg is a built-in class') if ismethod(object): - object = object.im_func + object = object.__func__ if isfunction(object): object = object.__code__ if istraceback(object): @@ -494,7 +493,7 @@ def findsource(object): raise IOError('could not find class definition') if ismethod(object): - object = object.im_func + object = object.__func__ if isfunction(object): object = object.__code__ if istraceback(object): @@ -744,7 +743,7 @@ def getfullargspec(func): """ if ismethod(func): - func = func.im_func + func = func.__func__ if not isfunction(func): raise TypeError('arg is not a Python function') args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__) diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py index f40a55328e3..aecb317efae 100644 --- a/Lib/lib-tk/Tkinter.py +++ b/Lib/lib-tk/Tkinter.py @@ -1081,7 +1081,7 @@ class Misc: f = CallWrapper(func, subst, self).__call__ name = repr(id(f)) try: - func = func.im_func + func = func.__func__ except AttributeError: pass try: diff --git a/Lib/pdb.py b/Lib/pdb.py index 3d79b4da1c4..f5bdb205c8e 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -345,8 +345,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): except: func = arg try: - if hasattr(func, 'im_func'): - func = func.im_func + if hasattr(func, '__func__'): + func = func.__func__ code = func.__code__ #use co_name to identify the bkpt (function names #could be aliased, but co_name is invariant) @@ -789,7 +789,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): print('Function', code.co_name, file=self.stdout) return # Is it an instance method? - try: code = value.im_func.__code__ + try: code = value.__func__.__code__ except: pass if code: print('Method', code.co_name, file=self.stdout) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 3cffa065cfb..51d627ea4dd 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -848,17 +848,17 @@ class HTMLDoc(Doc): note = '' skipdocs = 0 if inspect.ismethod(object): - imclass = object.im_class + imclass = object.__self__.__class__ if cl: if imclass is not cl: note = ' from ' + self.classlink(imclass, mod) else: - if object.im_self is not None: + if object.__self__ is not None: note = ' method of %s instance' % self.classlink( - object.im_self.__class__, mod) + object.__self__.__class__, mod) else: note = ' unbound %s method' % self.classlink(imclass,mod) - object = object.im_func + object = object.__func__ if name == realname: title = '%s' % (anchor, realname) @@ -1227,17 +1227,17 @@ class TextDoc(Doc): note = '' skipdocs = 0 if inspect.ismethod(object): - imclass = object.im_class + imclass = object.__self__.__class__ if cl: if imclass is not cl: note = ' from ' + classname(imclass, mod) else: - if object.im_self is not None: + if object.__self__ is not None: note = ' method of %s instance' % classname( - object.im_self.__class__, mod) + object.__self__.__class__, mod) else: note = ' unbound %s method' % classname(imclass,mod) - object = object.im_func + object = object.__func__ if name == realname: title = self.bold(realname) diff --git a/Lib/test/crashers/borrowed_ref_2.py b/Lib/test/crashers/borrowed_ref_2.py index f3ca35016da..6e403eb344c 100644 --- a/Lib/test/crashers/borrowed_ref_2.py +++ b/Lib/test/crashers/borrowed_ref_2.py @@ -33,6 +33,6 @@ lst = [None] * 1000000 i = 0 del a while 1: - c.d = 42 # segfaults in PyMethod_New(im_func=D.__set__, im_self=d) + c.d = 42 # segfaults in PyMethod_New(__func__=D.__set__, __self__=d) lst[i] = c.g # consume the free list of instancemethod objects i += 1 diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index e093ce8edfb..a518f162408 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -280,12 +280,12 @@ def test_dir(): c = C() vereq(interesting(dir(c)), cstuff) - #verify('im_self' in dir(C.Cmethod)) + #verify('__self__' in dir(C.Cmethod)) c.cdata = 2 c.cmethod = lambda self: 0 vereq(interesting(dir(c)), cstuff + ['cdata', 'cmethod']) - #verify('im_self' in dir(c.Cmethod)) + #verify('__self__' in dir(c.Cmethod)) class A(C): Adata = 1 @@ -293,13 +293,13 @@ def test_dir(): astuff = ['Adata', 'Amethod'] + cstuff vereq(interesting(dir(A)), astuff) - #verify('im_self' in dir(A.Amethod)) + #verify('__self__' in dir(A.Amethod)) a = A() vereq(interesting(dir(a)), astuff) a.adata = 42 a.amethod = lambda self: 3 vereq(interesting(dir(a)), astuff + ['adata', 'amethod']) - #verify('im_self' in dir(a.Amethod)) + #verify('__self__' in dir(a.Amethod)) # Try a module subclass. import sys @@ -1418,10 +1418,10 @@ def classmethods(): vereq(ff.__get__(0)(42), (int, 42)) # Test super() with classmethods (SF bug 535444) - veris(C.goo.im_self, C) - veris(D.goo.im_self, D) - veris(super(D,D).goo.im_self, D) - veris(super(D,d).goo.im_self, D) + veris(C.goo.__self__, C) + veris(D.goo.__self__, D) + veris(super(D,D).goo.__self__, D) + veris(super(D,d).goo.__self__, D) vereq(super(D,D).goo(), (D,)) vereq(super(D,d).goo(), (D,)) @@ -1507,7 +1507,7 @@ def classic(): r = repr(E().foo) verify(r.startswith("im_self; } -PyObject * -PyMethod_Class(PyObject *im) -{ - if (!PyMethod_Check(im)) { - PyErr_BadInternalCall(); - return NULL; - } - return ((PyMethodObject *)im)->im_class; -} - - -/* Method objects are used for two purposes: - (a) as bound instance methods (returned by instancename.methodname) - (b) as unbound methods (returned by ClassName.methodname) - In case (b), im_self is NULL +/* Method objects are used for bound instance methods returned by + instancename.methodname. ClassName.methodname returns an ordinary + function. */ static PyMethodObject *free_list; PyObject * -PyMethod_New(PyObject *func, PyObject *self, PyObject *klass) +PyMethod_New(PyObject *func, PyObject *self) { register PyMethodObject *im; if (!PyCallable_Check(func)) { PyErr_BadInternalCall(); return NULL; } + if (self == NULL) { + PyErr_BadInternalCall(); + return NULL; + } im = free_list; if (im != NULL) { free_list = (PyMethodObject *)(im->im_self); @@ -68,25 +60,21 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *klass) im->im_func = func; Py_XINCREF(self); im->im_self = self; - Py_XINCREF(klass); - im->im_class = klass; _PyObject_GC_TRACK(im); return (PyObject *)im; } /* Descriptors for PyMethod attributes */ -/* im_class, im_func and im_self are stored in the PyMethod object */ +/* im_func and im_self are stored in the PyMethod object */ #define OFF(x) offsetof(PyMethodObject, x) static PyMemberDef method_memberlist[] = { - {"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED, - "the class associated with a method"}, - {"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED, + {"__func__", T_OBJECT, OFF(im_func), READONLY|RESTRICTED, "the function (or other callable) implementing a method"}, - {"im_self", T_OBJECT, OFF(im_self), READONLY|RESTRICTED, - "the instance to which a method is bound; None for unbound methods"}, + {"__self__", T_OBJECT, OFF(im_self), READONLY|RESTRICTED, + "the instance to which a method is bound"}, {NULL} /* Sentinel */ }; @@ -141,7 +129,7 @@ method_getattro(PyObject *obj, PyObject *name) } PyDoc_STRVAR(method_doc, -"method(function, instance, class)\n\ +"method(function, instance)\n\ \n\ Create an instance method object."); @@ -150,27 +138,24 @@ method_new(PyTypeObject* type, PyObject* args, PyObject *kw) { PyObject *func; PyObject *self; - PyObject *classObj = NULL; if (!_PyArg_NoKeywords("instancemethod", kw)) return NULL; if (!PyArg_UnpackTuple(args, "method", 2, 3, - &func, &self, &classObj)) + &func, &self)) return NULL; if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "first argument must be callable"); return NULL; } - if (self == Py_None) - self = NULL; - if (self == NULL && classObj == NULL) { + if (self == NULL || self == Py_None) { PyErr_SetString(PyExc_TypeError, - "unbound methods must have non-NULL im_class"); + "self must not be None"); return NULL; } - return PyMethod_New(func, self, classObj); + return PyMethod_New(func, self); } static void @@ -181,7 +166,6 @@ method_dealloc(register PyMethodObject *im) PyObject_ClearWeakRefs((PyObject *)im); Py_DECREF(im->im_func); Py_XDECREF(im->im_self); - Py_XDECREF(im->im_class); im->im_self = (PyObject *)free_list; free_list = im; } @@ -225,10 +209,15 @@ method_repr(PyMethodObject *a) { PyObject *self = a->im_self; PyObject *func = a->im_func; - PyObject *klass = a->im_class; - PyObject *funcname = NULL, *klassname = NULL, *result = NULL; + PyObject *klass = (PyObject*)Py_Type(self); + PyObject *funcname = NULL ,*klassname = NULL, *result = NULL; char *defname = "?"; + if (self == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + funcname = PyObject_GetAttrString(func, "__name__"); if (funcname == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) @@ -239,6 +228,7 @@ method_repr(PyMethodObject *a) Py_DECREF(funcname); funcname = NULL; } + if (klass == NULL) klassname = NULL; else { @@ -253,16 +243,12 @@ method_repr(PyMethodObject *a) klassname = NULL; } } - if (self == NULL) - result = PyUnicode_FromFormat("", - klassname, defname, - funcname, defname); - else { - /* XXX Shouldn't use repr()/%R here! */ - result = PyUnicode_FromFormat("", - klassname, defname, - funcname, defname, self); - } + + /* XXX Shouldn't use repr()/%R here! */ + result = PyUnicode_FromFormat("", + klassname, defname, + funcname, defname, self); + Py_XDECREF(funcname); Py_XDECREF(klassname); return result; @@ -292,92 +278,19 @@ method_traverse(PyMethodObject *im, visitproc visit, void *arg) { Py_VISIT(im->im_func); Py_VISIT(im->im_self); - Py_VISIT(im->im_class); return 0; } -static void -getclassname(PyObject *klass, char *buf, int bufsize) -{ - PyObject *name; - - assert(bufsize > 1); - strcpy(buf, "?"); /* Default outcome */ - if (klass == NULL) - return; - name = PyObject_GetAttrString(klass, "__name__"); - if (name == NULL) { - /* This function cannot return an exception */ - PyErr_Clear(); - return; - } - if (PyUnicode_Check(name)) { - strncpy(buf, PyUnicode_AsString(name), bufsize); - buf[bufsize-1] = '\0'; - } - Py_DECREF(name); -} - -static void -getinstclassname(PyObject *inst, char *buf, int bufsize) -{ - PyObject *klass; - - if (inst == NULL) { - assert(bufsize > 0 && (size_t)bufsize > strlen("nothing")); - strcpy(buf, "nothing"); - return; - } - - klass = PyObject_GetAttrString(inst, "__class__"); - if (klass == NULL) { - /* This function cannot return an exception */ - PyErr_Clear(); - klass = (PyObject *)(inst->ob_type); - Py_INCREF(klass); - } - getclassname(klass, buf, bufsize); - Py_XDECREF(klass); -} - static PyObject * method_call(PyObject *func, PyObject *arg, PyObject *kw) { PyObject *self = PyMethod_GET_SELF(func); - PyObject *klass = PyMethod_GET_CLASS(func); PyObject *result; func = PyMethod_GET_FUNCTION(func); if (self == NULL) { - /* Unbound methods must be called with an instance of - the class (or a derived class) as first argument */ - int ok; - if (PyTuple_Size(arg) >= 1) - self = PyTuple_GET_ITEM(arg, 0); - if (self == NULL) - ok = 0; - else { - ok = PyObject_IsInstance(self, klass); - if (ok < 0) - return NULL; - } - if (!ok) { - char clsbuf[256]; - char instbuf[256]; - getclassname(klass, clsbuf, sizeof(clsbuf)); - getinstclassname(self, instbuf, sizeof(instbuf)); - PyErr_Format(PyExc_TypeError, - "unbound method %s%s must be called with " - "%s instance as first argument " - "(got %s%s instead)", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - clsbuf, - instbuf, - self == NULL ? "" : " instance"); - return NULL; - } - Py_INCREF(arg); + PyErr_BadInternalCall(); + return NULL; } else { Py_ssize_t argcount = PyTuple_Size(arg); @@ -402,27 +315,15 @@ method_call(PyObject *func, PyObject *arg, PyObject *kw) static PyObject * method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) { - /* Don't rebind an already bound method, or an unbound method - of a class that's not a base class of cls. */ - + /* Don't rebind an already bound method of a class that's not a base + class of cls. */ if (PyMethod_GET_SELF(meth) != NULL) { /* Already bound */ Py_INCREF(meth); return meth; } - /* No, it is an unbound method */ - if (PyMethod_GET_CLASS(meth) != NULL && cls != NULL) { - /* Do subclass test. If it fails, return meth unchanged. */ - int ok = PyObject_IsSubclass(cls, PyMethod_GET_CLASS(meth)); - if (ok < 0) - return NULL; - if (!ok) { - Py_INCREF(meth); - return meth; - } - } /* Bind it to obj */ - return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj, cls); + return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj); } PyTypeObject PyMethod_Type = { diff --git a/Objects/funcobject.c b/Objects/funcobject.c index f9b0346eaa4..ac68edce39c 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -647,7 +647,7 @@ func_descr_get(PyObject *func, PyObject *obj, PyObject *type) Py_INCREF(func); return func; } - return PyMethod_New(func, obj, type); + return PyMethod_New(func, obj); } PyTypeObject PyFunction_Type = { @@ -751,8 +751,7 @@ cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) } if (type == NULL) type = (PyObject *)(Py_Type(obj)); - return PyMethod_New(cm->cm_callable, - type, (PyObject *)(Py_Type(type))); + return PyMethod_New(cm->cm_callable, type); } static int