]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Removed the API to create unbound methods and simplified the API for bound methods...
authorChristian Heimes <christian@cheimes.de>
Tue, 27 Nov 2007 10:40:20 +0000 (10:40 +0000)
committerChristian Heimes <christian@cheimes.de>
Tue, 27 Nov 2007 10:40:20 +0000 (10:40 +0000)
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.

23 files changed:
Doc/library/inspect.rst
Doc/library/new.rst
Doc/library/stdtypes.rst
Doc/reference/datamodel.rst
Doc/tutorial/classes.rst
Include/classobject.h
Lib/ctypes/test/test_callbacks.py
Lib/dis.py
Lib/doctest.py
Lib/idlelib/CallTips.py
Lib/inspect.py
Lib/lib-tk/Tkinter.py
Lib/pdb.py
Lib/pydoc.py
Lib/test/crashers/borrowed_ref_2.py
Lib/test/test_descr.py
Lib/test/test_funcattrs.py
Lib/test/test_new.py
Lib/test/test_profilehooks.py
Lib/test/test_pyclbr.py
Misc/NEWS
Objects/classobject.c
Objects/funcobject.c

index cf14de97202ac8b072f59a76ad1f22a94f1813a3..988b73775e9b335e1f8b7a6281f9f670fcfb58e5 100644 (file)
@@ -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)
index 6153ff148bc4dfec12c078252622ae82618335d0..6c5a4bf8176c842c19855363113f9504e13729e2 100644 (file)
@@ -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]]])
index e6f7e7b52ad61ce378dcbca4a131ba542e33cec4..1e81ed935f96bab583f2bbcbd9bd0f373108ab78 100644 (file)
@@ -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.
 
index 1e85f8305e14170b2bba1178205baa1f1f94088f..75cb52f5d3e24a5e179d179ae3fb7db273104e06 100644 (file)
@@ -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
index ef6498e885e5d486c83bf6d43ee73901a48210f2..4e954195a0756a5e1b278014e218b5929e3fab0b 100644 (file)
@@ -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.
 
 
index 885c43e4cfd28494029c33f93bb4699a9eea4ca3..e6ca421a5be32391e8d3f63e08ad6f7f557111f3 100644 (file)
@@ -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
 }
index d870eb424c415531147319dfea95284677bf555d..bf580ae8bd8252dfea6836bd7d9e8681ab369405 100644 (file)
@@ -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:
index 4cf452a097ab9d1577e9d5cbe2caca1247efeb29..6d52694a75deddfae6ccbbe009c1d7369510577d 100644 (file)
@@ -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__'):
index 5b1807301af6a05e3b8730a1a18b21aa66731b6d..f135027248007cef93278f5561df291d0f3d1350 100644 (file)
@@ -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
index aee7e612871a0d5325e79d2cbbbefb4d7dd21177..cda2be979d2df7e44756c1169c2fcfd0bfae8b3e 100644 (file)
@@ -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)
index 3a95796792fcf864b7c3d8a8d9af16078f3ba6b2..a1910e4ff960a165620647ae18cdc973c7d4a5e7 100644 (file)
@@ -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__)
index f40a55328e37d2a23008a0e16ab20d940993d18e..aecb317efaee576ef01b69c4e56d1d65d5b94625 100644 (file)
@@ -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:
index 3d79b4da1c4b5a83048e1e693fc559325617f32f..f5bdb205c8e283a85e7317aaa3a9b6e7f8bdc7ec 100755 (executable)
@@ -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)
index 3cffa065cfb1a35201702578907c3fe6f8ac2bb5..51d627ea4dd43b53cddf8a89d6e02136fcf190f4 100755 (executable)
@@ -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 = '<a name="%s"><strong>%s</strong></a>' % (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)
index f3ca35016da08a1b47d4df2571b322af4f12414f..6e403eb344c1845823a66edb2a7f3793b6a37118 100644 (file)
@@ -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
index e093ce8edfb689481a5a86885e2b7f8dd7d8e7bc..a518f162408d6063e3af1c8cc7c448c01bd9942f 100644 (file)
@@ -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("<bound method E.foo "), r)
     r = repr(C.foo.__get__(C()))
-    verify(r.startswith("<bound method ?.foo "), r)
+    verify(r.startswith("<bound method "), r)
 
 def compattr():
     if verbose: print("Testing computed attributes...")
@@ -1687,7 +1687,7 @@ def methods():
     vereq(d2.goo(), 1)
     class E(object):
         foo = C.foo
-    vereq(E().foo.im_func, C.foo) # i.e., unbound
+    vereq(E().foo.__func__, C.foo) # i.e., unbound
     r = repr(C.foo.__get__(C(1)))
     verify(r.startswith("<bound method "), r)
 
@@ -1864,17 +1864,6 @@ def recursions():
 ##         raise TestFailed, "expected a RuntimeError for print recursion"
 ##     sys.stdout = test_stdout
 
-    # Bug #1202533.
-    class A(object):
-        pass
-    A.__mul__ = new.instancemethod(lambda self, x: self * x, None, A)
-    try:
-        A()*2
-    except RuntimeError:
-        pass
-    else:
-        raise TestFailed("expected a RuntimeError")
-
 def weakrefs():
     if verbose: print("Testing weak references...")
     import weakref
index b9b2e6e5569630c571f27a34742a1dd9a6825e42..3d0d4aa40e2b54f9b004624f7dfca1a456cf17df 100644 (file)
@@ -104,11 +104,12 @@ else: raise TestFailed
 if f2.a.one != f1.a.one != F.a.one != 11:
     raise TestFailed
 
-# im_func may not be a Python method!
+# __func__ may not be a Python method!
 import new
-F.id = new.instancemethod(id, None, F)
+F.id = id
 
 eff = F()
+eff.id = new.instancemethod(id, eff)
 if eff.id() != id(eff):
     raise TestFailed
 
@@ -296,32 +297,32 @@ def test_func_dict():
     verify(f.__dict__ == {'world': 'hello'})
     cantset(f, "__dict__", None)
 
-def test_im_class():
+def test___self__():
     class C:
         def foo(self): pass
-    #verify(C.foo.im_class is C)
-    verify(C().foo.im_class is C)
-    #cantset(C.foo, "im_class", C)
-    cantset(C().foo, "im_class", C)
+    #verify(C.foo.__self__.__class__ is C)
+    verify(C().foo.__self__.__class__ is C)
+    #cantset(C.foo, "__self__.__class__", C)
+    cantset(C().foo, "__self__.__class__", C)
 
-def test_im_func():
+def test___func__():
     def foo(self): pass
     class C:
         pass
     C.foo = foo
-    #verify(C.foo.im_func is foo)
-    verify(C().foo.im_func is foo)
-    #cantset(C.foo, "im_func", foo)
-    cantset(C().foo, "im_func", foo)
+    #verify(C.foo.__func__ is foo)
+    verify(C().foo.__func__ is foo)
+    #cantset(C.foo, "__func__", foo)
+    cantset(C().foo, "__func__", foo)
 
-def test_im_self():
+def test___self__():
     class C:
         def foo(self): pass
-    #verify(C.foo.im_self is None)
+    #verify(C.foo.__self__ is None)
     c = C()
-    #verify(c.foo.im_self is c)
-    #cantset(C.foo, "im_self", None)
-    #cantset(c.foo, "im_self", c)
+    #verify(c.foo.__self__ is c)
+    #cantset(C.foo, "__self__", None)
+    #cantset(c.foo, "__self__", c)
 
 def test_im_dict():
     class C:
@@ -358,9 +359,9 @@ def testmore():
     test_func_defaults()
     test_func_dict()
     # Tests for instance method attributes
-    test_im_class()
-    test_im_func()
-    test_im_self()
+    test___self__()
+    test___func__()
+    test___self__()
     test_im_dict()
     test_im_doc()
     test_im_name()
index 797a8c349f3181577913de04de0f11b27fe42851..8e1d49db9ee4a990db7b12558d27ea8c0d32f8af 100644 (file)
@@ -25,7 +25,7 @@ class NewTest(unittest.TestCase):
         # new.instancemethod()
         c = C()
         c.yolks = 3
-        im = new.instancemethod(break_yolks, c, C)
+        im = new.instancemethod(break_yolks, c)
 
         self.assertEqual(c.get_yolks(), 3,
             'Broken call of hand-crafted class instance')
@@ -43,7 +43,7 @@ class NewTest(unittest.TestCase):
         self.assertEqual(c.get_yolks(), -1)
 
         # Verify that dangerous instance method creation is forbidden
-        self.assertRaises(TypeError, new.instancemethod, break_yolks, None)
+        self.assertRaises(TypeError, new.instancemethod, None)
 
         # Verify that instancemethod() doesn't allow keyword args
         self.assertRaises(TypeError, new.instancemethod, break_yolks, c, kw=1)
index 0f5616d0a7c10a2720f19e5291e8dbf5d4c1ecf3..3a17dc7390e908c76efde3f6fa7261e3ef79d7cd 100644 (file)
@@ -31,7 +31,7 @@ class HookWatcher:
 
     def get_events(self):
         """Remove calls to add_event()."""
-        disallowed = [ident(self.add_event.im_func), ident(ident)]
+        disallowed = [ident(self.add_event.__func__), ident(ident)]
         self.frames = None
 
         return [item for item in self.events if item[2] not in disallowed]
index bcb79880d3bdff452ac06b7f509dccf7ce7e50cd..b88cb7e90beb01df5c154bf85f155942c0cf3d3b 100644 (file)
@@ -67,7 +67,7 @@ class PyclbrTest(TestCase):
             if isinstance(obj, MethodType):
                 # could be a classmethod
                 if (not isinstance(classdict[name], ClassMethodType) or
-                    obj.im_self is not oclass):
+                    obj.__self__ is not oclass):
                     return False
             elif not isinstance(obj, FunctionType):
                 return False
index e0d3f8b3b5c1f30b9d0da630adc0598566bf154c..83ce320c4abe13a826e06b58ce4e4864b327a188 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,12 @@ Core and Builtins
 - Renamed structmember.h WRITE_RESTRICTED to PY_WRITE_RESTRICTED to work
   around a name clash with VS 2008 on Windows.
 
+- Unbound methods are gone for good. ClassObject.method returns an ordinary
+  function object, instance.method still returns a bound method object.
+  The API of bound methods is cleaned up, too. The im_class attribute is
+  removed and im_func + im_self are renamed to __func__ and __self__. The
+  factory PyMethod_New takes only func and instance as argument.
+
 
 Extension Modules
 -----------------
index 2db898a266af9161ac363c4ac4dd60977f69aef0..5362fbcd6ffea3f5d03ba1c1a21aaded633c71fb 100644 (file)
@@ -26,33 +26,25 @@ PyMethod_Self(PyObject *im)
        return ((PyMethodObject *)im)->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("<unbound method %V.%V>",
-                                             klassname, defname,
-                                             funcname, defname);
-       else {
-               /* XXX Shouldn't use repr()/%R here! */
-               result = PyUnicode_FromFormat("<bound method %V.%V of %R>",
-                                             klassname, defname,
-                                             funcname, defname, self);
-       }
+
+       /* XXX Shouldn't use repr()/%R here! */
+       result = PyUnicode_FromFormat("<bound method %V.%V of %R>",
+                                     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 = {
index f9b0346eaa4b60f6861dda71033b78b0e9c852b4..ac68edce39c121c0d690158422f83bd78006d4c5 100644 (file)
@@ -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