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.
This commit is contained in:
parent
0d3fb8a944
commit
ff737954f3
|
@ -49,14 +49,11 @@ attributes:
|
||||||
| | __name__ | name with which this |
|
| | __name__ | name with which this |
|
||||||
| | | method was defined |
|
| | | method was defined |
|
||||||
+-----------+-----------------+---------------------------+
|
+-----------+-----------------+---------------------------+
|
||||||
| | im_class | class object that asked |
|
| | __func__ | function object |
|
||||||
| | | for this method |
|
|
||||||
+-----------+-----------------+---------------------------+
|
|
||||||
| | im_func | function object |
|
|
||||||
| | | containing implementation |
|
| | | containing implementation |
|
||||||
| | | of method |
|
| | | of method |
|
||||||
+-----------+-----------------+---------------------------+
|
+-----------+-----------------+---------------------------+
|
||||||
| | im_self | instance to which this |
|
| | __self__ | instance to which this |
|
||||||
| | | method is bound, or |
|
| | | method is bound, or |
|
||||||
| | | ``None`` |
|
| | | ``None`` |
|
||||||
+-----------+-----------------+---------------------------+
|
+-----------+-----------------+---------------------------+
|
||||||
|
@ -264,7 +261,7 @@ attributes:
|
||||||
Methods implemented via descriptors that also pass one of the other tests
|
Methods implemented via descriptors that also pass one of the other tests
|
||||||
return false from the :func:`ismethoddescriptor` test, simply because the
|
return false from the :func:`ismethoddescriptor` test, simply because the
|
||||||
other tests promise more -- you can, e.g., count on having 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)
|
.. function:: isdatadescriptor(object)
|
||||||
|
|
|
@ -17,10 +17,10 @@ non-sensical arguments which crash the interpreter when the object is used.
|
||||||
The :mod:`new` module defines the following functions:
|
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
|
This function will return a method object, bound to *instance*.
|
||||||
*instance* is ``None``. *function* must be callable.
|
*function* must be callable.
|
||||||
|
|
||||||
|
|
||||||
.. function:: function(code, globals[, name[, argdefs[, closure]]])
|
.. function:: function(code, globals[, name[, argdefs[, closure]]])
|
||||||
|
|
|
@ -2216,21 +2216,21 @@ instance methods. Built-in methods are described with the types that support
|
||||||
them.
|
them.
|
||||||
|
|
||||||
The implementation adds two special read-only attributes to class instance
|
The implementation adds two special read-only attributes to class instance
|
||||||
methods: ``m.im_self`` is the object on which the method operates, and
|
methods: ``m.__self__`` is the object on which the method operates, and
|
||||||
``m.im_func`` is the function implementing the method. Calling ``m(arg-1,
|
``m.__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-2, ..., arg-n)`` is completely equivalent to calling ``m.__func__(
|
||||||
arg-1, arg-2, ..., arg-n)``.
|
m.__self__, arg-1, arg-2, ..., arg-n)``.
|
||||||
|
|
||||||
Class instance methods are either *bound* or *unbound*, referring to whether the
|
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
|
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,
|
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
|
``self`` must be an instance of the unbound method's class (or a subclass of
|
||||||
that class), otherwise a :exc:`TypeError` is raised.
|
that class), otherwise a :exc:`TypeError` is raised.
|
||||||
|
|
||||||
Like function objects, methods objects support getting arbitrary attributes.
|
Like function objects, methods objects support getting arbitrary attributes.
|
||||||
However, since method attributes are actually stored on the underlying function
|
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
|
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
|
:exc:`TypeError` being raised. In order to set a method attribute, you need to
|
||||||
explicitly set it on the underlying function object::
|
explicitly set it on the underlying function object::
|
||||||
|
@ -2240,7 +2240,7 @@ explicitly set it on the underlying function object::
|
||||||
pass
|
pass
|
||||||
|
|
||||||
c = C()
|
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.
|
See :ref:`types` for more information.
|
||||||
|
|
||||||
|
|
|
@ -538,20 +538,18 @@ Callable types
|
||||||
A user-defined method object combines a class, a class instance (or ``None``)
|
A user-defined method object combines a class, a class instance (or ``None``)
|
||||||
and any callable object (normally a user-defined function).
|
and any callable object (normally a user-defined function).
|
||||||
|
|
||||||
Special read-only attributes: :attr:`im_self` is the class instance object,
|
Special read-only attributes: :attr:`__self__` is the class instance object,
|
||||||
:attr:`im_func` is the function object; :attr:`im_class` is the class of
|
:attr:`__func__` is the function object; :attr:`__doc__` is the method's
|
||||||
:attr:`im_self` for bound methods or the class that asked for the method for
|
documentation (same as ``__func__.__doc__``); :attr:`__name__` is the
|
||||||
unbound methods; :attr:`__doc__` is the method's documentation (same as
|
method name (same as ``__func__.__name__``); :attr:`__module__` is the
|
||||||
``im_func.__doc__``); :attr:`__name__` is the method name (same as
|
name of the module the method was defined in, or ``None`` if unavailable.
|
||||||
``im_func.__name__``); :attr:`__module__` is the name of the module the method
|
|
||||||
was defined in, or ``None`` if unavailable.
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: __doc__ (method attribute)
|
single: __doc__ (method attribute)
|
||||||
single: __name__ (method attribute)
|
single: __name__ (method attribute)
|
||||||
single: __module__ (method attribute)
|
single: __module__ (method attribute)
|
||||||
single: im_func (method attribute)
|
single: __func__ (method attribute)
|
||||||
single: im_self (method attribute)
|
single: __self__ (method attribute)
|
||||||
|
|
||||||
Methods also support accessing (but not setting) the arbitrary function
|
Methods also support accessing (but not setting) the arbitrary function
|
||||||
attributes on the underlying function object.
|
attributes on the underlying function object.
|
||||||
|
@ -565,49 +563,46 @@ Callable types
|
||||||
the original method object is used as it is.
|
the original method object is used as it is.
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: im_class (method attribute)
|
single: __func__ (method attribute)
|
||||||
single: im_func (method attribute)
|
single: __self__ (method attribute)
|
||||||
single: im_self (method attribute)
|
|
||||||
|
|
||||||
When a user-defined method object is created by retrieving a user-defined
|
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
|
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
|
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
|
instances, its :attr:`__self__` attribute is the instance, and the method
|
||||||
object is said to be bound. In either case, the new method's
|
object is said to be bound. Its :attr:`__func__` attribute is the
|
||||||
:attr:`im_class` attribute is the class from which the retrieval takes
|
original function object.
|
||||||
place, and its :attr:`im_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
|
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,
|
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
|
except that the :attr:`__func__` attribute of the new instance is not the
|
||||||
original method object but its :attr:`im_func` attribute.
|
original method object but its :attr:`__func__` attribute.
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: im_class (method attribute)
|
single: __func__ (method attribute)
|
||||||
single: im_func (method attribute)
|
single: __self__ (method attribute)
|
||||||
single: im_self (method attribute)
|
|
||||||
|
|
||||||
When a user-defined method object is created by retrieving a class method object
|
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
|
from a class or instance, its :attr:`__self__` attribute is the class itself (the
|
||||||
same as the :attr:`im_class` attribute), and its :attr:`im_func` attribute is
|
same as the :attr:`im_class` attribute), and its :attr:`__func__` attribute is
|
||||||
the function object underlying the class method.
|
the function object underlying the class method.
|
||||||
|
|
||||||
When an unbound user-defined method object is called, the underlying function
|
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
|
be an instance of the proper class (:attr:`im_class`) or of a derived class
|
||||||
thereof.
|
thereof.
|
||||||
|
|
||||||
When a bound user-defined method object is called, the underlying function
|
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
|
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
|
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)``.
|
: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
|
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)``
|
that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to calling ``f(C,1)``
|
||||||
where ``f`` is the underlying function.
|
where ``f`` is the underlying function.
|
||||||
|
|
||||||
|
@ -741,7 +736,7 @@ Custom classes
|
||||||
transformed into an unbound user-defined method object whose :attr:`im_class`
|
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
|
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`
|
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
|
static method object, it is transformed into the object wrapped by the static
|
||||||
method object. See section :ref:`descriptors` for another way in which
|
method object. See section :ref:`descriptors` for another way in which
|
||||||
attributes retrieved from a class may differ from those actually contained in
|
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
|
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
|
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
|
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
|
objects are also transformed, as if they had been retrieved from class
|
||||||
:class:`C`; see above under "Classes". See section :ref:`descriptors` for
|
:class:`C`; see above under "Classes". See section :ref:`descriptors` for
|
||||||
another way in which attributes of a class retrieved via its instances may
|
another way in which attributes of a class retrieved via its instances may
|
||||||
|
|
|
@ -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
|
.. % \code{sys.stdin} will not cause the interpreter to read further input
|
||||||
.. % from it.)
|
.. % from it.)
|
||||||
|
|
||||||
Instance method objects have attributes, too: ``m.im_self`` is the instance
|
Instance method objects have attributes, too: ``m.__self__`` is the instance
|
||||||
object with the method :meth:`m`, and ``m.im_func`` is the function object
|
object with the method :meth:`m`, and ``m.__func__`` is the function object
|
||||||
corresponding to the method.
|
corresponding to the method.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) */
|
/* Revealing some structures (not for general use) */
|
||||||
|
|
||||||
|
@ -11,8 +11,7 @@ extern "C" {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *im_func; /* The callable object implementing the method */
|
PyObject *im_func; /* The callable object implementing the method */
|
||||||
PyObject *im_self; /* The instance it is bound to, or NULL */
|
PyObject *im_self; /* The instance it is bound to */
|
||||||
PyObject *im_class; /* The class that asked for the method */
|
|
||||||
PyObject *im_weakreflist; /* List of weak references */
|
PyObject *im_weakreflist; /* List of weak references */
|
||||||
} PyMethodObject;
|
} PyMethodObject;
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ PyAPI_DATA(PyTypeObject) PyMethod_Type;
|
||||||
|
|
||||||
#define PyMethod_Check(op) ((op)->ob_type == &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_Function(PyObject *);
|
||||||
PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *);
|
PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *);
|
||||||
|
@ -32,8 +31,6 @@ PyAPI_FUNC(PyObject *) PyMethod_Class(PyObject *);
|
||||||
(((PyMethodObject *)meth) -> im_func)
|
(((PyMethodObject *)meth) -> im_func)
|
||||||
#define PyMethod_GET_SELF(meth) \
|
#define PyMethod_GET_SELF(meth) \
|
||||||
(((PyMethodObject *)meth) -> im_self)
|
(((PyMethodObject *)meth) -> im_self)
|
||||||
#define PyMethod_GET_CLASS(meth) \
|
|
||||||
(((PyMethodObject *)meth) -> im_class)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Callbacks(unittest.TestCase):
|
||||||
return args[-1]
|
return args[-1]
|
||||||
|
|
||||||
def check_type(self, typ, arg):
|
def check_type(self, typ, arg):
|
||||||
PROTO = self.functype.im_func(typ, typ)
|
PROTO = self.functype.__func__(typ, typ)
|
||||||
result = PROTO(self.callback)(arg)
|
result = PROTO(self.callback)(arg)
|
||||||
if typ == c_float:
|
if typ == c_float:
|
||||||
self.failUnlessAlmostEqual(result, arg, places=5)
|
self.failUnlessAlmostEqual(result, arg, places=5)
|
||||||
|
@ -22,7 +22,7 @@ class Callbacks(unittest.TestCase):
|
||||||
self.failUnlessEqual(self.got_args, (arg,))
|
self.failUnlessEqual(self.got_args, (arg,))
|
||||||
self.failUnlessEqual(result, 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)
|
result = PROTO(self.callback)(-3, arg)
|
||||||
if typ == c_float:
|
if typ == c_float:
|
||||||
self.failUnlessAlmostEqual(result, arg, places=5)
|
self.failUnlessAlmostEqual(result, arg, places=5)
|
||||||
|
@ -110,12 +110,12 @@ class Callbacks(unittest.TestCase):
|
||||||
# functions, the type must have a non-NULL stgdict->setfunc.
|
# functions, the type must have a non-NULL stgdict->setfunc.
|
||||||
# POINTER(c_double), for example, is not supported.
|
# 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
|
# The type is checked when the prototype is called
|
||||||
self.assertRaises(TypeError, prototype, lambda: None)
|
self.assertRaises(TypeError, prototype, lambda: None)
|
||||||
|
|
||||||
def test_unsupported_restype_2(self):
|
def test_unsupported_restype_2(self):
|
||||||
prototype = self.functype.im_func(object)
|
prototype = self.functype.__func__(object)
|
||||||
self.assertRaises(TypeError, prototype, lambda: None)
|
self.assertRaises(TypeError, prototype, lambda: None)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -18,8 +18,8 @@ def dis(x=None):
|
||||||
if x is None:
|
if x is None:
|
||||||
distb()
|
distb()
|
||||||
return
|
return
|
||||||
if hasattr(x, 'im_func'):
|
if hasattr(x, '__func__'):
|
||||||
x = x.im_func
|
x = x.__func__
|
||||||
if hasattr(x, '__code__'):
|
if hasattr(x, '__code__'):
|
||||||
x = x.__code__
|
x = x.__code__
|
||||||
if hasattr(x, '__dict__'):
|
if hasattr(x, '__dict__'):
|
||||||
|
|
|
@ -913,7 +913,7 @@ class DocTestFinder:
|
||||||
if isinstance(val, staticmethod):
|
if isinstance(val, staticmethod):
|
||||||
val = getattr(obj, valname)
|
val = getattr(obj, valname)
|
||||||
if isinstance(val, classmethod):
|
if isinstance(val, classmethod):
|
||||||
val = getattr(obj, valname).im_func
|
val = getattr(obj, valname).__func__
|
||||||
|
|
||||||
# Recurse to methods, properties, and nested classes.
|
# Recurse to methods, properties, and nested classes.
|
||||||
if ((inspect.isfunction(val) or inspect.isclass(val) or
|
if ((inspect.isfunction(val) or inspect.isclass(val) or
|
||||||
|
@ -985,7 +985,7 @@ class DocTestFinder:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Find the line number for functions & methods.
|
# 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.isfunction(obj): obj = obj.__code__
|
||||||
if inspect.istraceback(obj): obj = obj.tb_frame
|
if inspect.istraceback(obj): obj = obj.tb_frame
|
||||||
if inspect.isframe(obj): obj = obj.f_code
|
if inspect.isframe(obj): obj = obj.f_code
|
||||||
|
|
|
@ -116,7 +116,7 @@ class CallTips:
|
||||||
def _find_constructor(class_ob):
|
def _find_constructor(class_ob):
|
||||||
"Find the nearest __init__() in the class tree."
|
"Find the nearest __init__() in the class tree."
|
||||||
try:
|
try:
|
||||||
return class_ob.__init__.im_func
|
return class_ob.__init__.__func__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
for base in class_ob.__bases__:
|
for base in class_ob.__bases__:
|
||||||
init = _find_constructor(base)
|
init = _find_constructor(base)
|
||||||
|
@ -133,7 +133,7 @@ def get_argspec(ob):
|
||||||
if fob is None:
|
if fob is None:
|
||||||
fob = lambda: None
|
fob = lambda: None
|
||||||
elif isinstance(ob, types.MethodType):
|
elif isinstance(ob, types.MethodType):
|
||||||
fob = ob.im_func
|
fob = ob.__func__
|
||||||
else:
|
else:
|
||||||
fob = ob
|
fob = ob
|
||||||
if isinstance(fob, (types.FunctionType, types.LambdaType)):
|
if isinstance(fob, (types.FunctionType, types.LambdaType)):
|
||||||
|
@ -183,7 +183,7 @@ def main():
|
||||||
name = t.__name__
|
name = t.__name__
|
||||||
# exercise fetch_tip(), not just get_argspec()
|
# exercise fetch_tip(), not just get_argspec()
|
||||||
try:
|
try:
|
||||||
qualified_name = "%s.%s" % (t.im_class.__name__, name)
|
qualified_name = "%s.%s" % (t.__self__.__class__.__name__, name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
qualified_name = name
|
qualified_name = name
|
||||||
argspec = ct.fetch_tip(qualified_name)
|
argspec = ct.fetch_tip(qualified_name)
|
||||||
|
|
|
@ -55,9 +55,8 @@ def ismethod(object):
|
||||||
Instance method objects provide these attributes:
|
Instance method objects provide these attributes:
|
||||||
__doc__ documentation string
|
__doc__ documentation string
|
||||||
__name__ name with which this method was defined
|
__name__ name with which this method was defined
|
||||||
im_class class object in which this method belongs
|
__func__ function object containing implementation of method
|
||||||
im_func function object containing implementation of method
|
__self__ instance to which this method is bound"""
|
||||||
im_self instance to which this method is bound"""
|
|
||||||
return isinstance(object, types.MethodType)
|
return isinstance(object, types.MethodType)
|
||||||
|
|
||||||
def ismethoddescriptor(object):
|
def ismethoddescriptor(object):
|
||||||
|
@ -73,7 +72,7 @@ def ismethoddescriptor(object):
|
||||||
Methods implemented via descriptors that also pass one of the other
|
Methods implemented via descriptors that also pass one of the other
|
||||||
tests return false from the ismethoddescriptor() test, simply because
|
tests return false from the ismethoddescriptor() test, simply because
|
||||||
the other tests promise more -- you can, e.g., count on having the
|
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__")
|
return (hasattr(object, "__get__")
|
||||||
and not hasattr(object, "__set__") # else it's a data descriptor
|
and not hasattr(object, "__set__") # else it's a data descriptor
|
||||||
and not ismethod(object) # mutual exclusion
|
and not ismethod(object) # mutual exclusion
|
||||||
|
@ -351,7 +350,7 @@ def getfile(object):
|
||||||
return object.__file__
|
return object.__file__
|
||||||
raise TypeError('arg is a built-in class')
|
raise TypeError('arg is a built-in class')
|
||||||
if ismethod(object):
|
if ismethod(object):
|
||||||
object = object.im_func
|
object = object.__func__
|
||||||
if isfunction(object):
|
if isfunction(object):
|
||||||
object = object.__code__
|
object = object.__code__
|
||||||
if istraceback(object):
|
if istraceback(object):
|
||||||
|
@ -494,7 +493,7 @@ def findsource(object):
|
||||||
raise IOError('could not find class definition')
|
raise IOError('could not find class definition')
|
||||||
|
|
||||||
if ismethod(object):
|
if ismethod(object):
|
||||||
object = object.im_func
|
object = object.__func__
|
||||||
if isfunction(object):
|
if isfunction(object):
|
||||||
object = object.__code__
|
object = object.__code__
|
||||||
if istraceback(object):
|
if istraceback(object):
|
||||||
|
@ -744,7 +743,7 @@ def getfullargspec(func):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if ismethod(func):
|
if ismethod(func):
|
||||||
func = func.im_func
|
func = func.__func__
|
||||||
if not isfunction(func):
|
if not isfunction(func):
|
||||||
raise TypeError('arg is not a Python function')
|
raise TypeError('arg is not a Python function')
|
||||||
args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__)
|
args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__)
|
||||||
|
|
|
@ -1081,7 +1081,7 @@ class Misc:
|
||||||
f = CallWrapper(func, subst, self).__call__
|
f = CallWrapper(func, subst, self).__call__
|
||||||
name = repr(id(f))
|
name = repr(id(f))
|
||||||
try:
|
try:
|
||||||
func = func.im_func
|
func = func.__func__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -345,8 +345,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
except:
|
except:
|
||||||
func = arg
|
func = arg
|
||||||
try:
|
try:
|
||||||
if hasattr(func, 'im_func'):
|
if hasattr(func, '__func__'):
|
||||||
func = func.im_func
|
func = func.__func__
|
||||||
code = func.__code__
|
code = func.__code__
|
||||||
#use co_name to identify the bkpt (function names
|
#use co_name to identify the bkpt (function names
|
||||||
#could be aliased, but co_name is invariant)
|
#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)
|
print('Function', code.co_name, file=self.stdout)
|
||||||
return
|
return
|
||||||
# Is it an instance method?
|
# Is it an instance method?
|
||||||
try: code = value.im_func.__code__
|
try: code = value.__func__.__code__
|
||||||
except: pass
|
except: pass
|
||||||
if code:
|
if code:
|
||||||
print('Method', code.co_name, file=self.stdout)
|
print('Method', code.co_name, file=self.stdout)
|
||||||
|
|
16
Lib/pydoc.py
16
Lib/pydoc.py
|
@ -848,17 +848,17 @@ class HTMLDoc(Doc):
|
||||||
note = ''
|
note = ''
|
||||||
skipdocs = 0
|
skipdocs = 0
|
||||||
if inspect.ismethod(object):
|
if inspect.ismethod(object):
|
||||||
imclass = object.im_class
|
imclass = object.__self__.__class__
|
||||||
if cl:
|
if cl:
|
||||||
if imclass is not cl:
|
if imclass is not cl:
|
||||||
note = ' from ' + self.classlink(imclass, mod)
|
note = ' from ' + self.classlink(imclass, mod)
|
||||||
else:
|
else:
|
||||||
if object.im_self is not None:
|
if object.__self__ is not None:
|
||||||
note = ' method of %s instance' % self.classlink(
|
note = ' method of %s instance' % self.classlink(
|
||||||
object.im_self.__class__, mod)
|
object.__self__.__class__, mod)
|
||||||
else:
|
else:
|
||||||
note = ' unbound %s method' % self.classlink(imclass,mod)
|
note = ' unbound %s method' % self.classlink(imclass,mod)
|
||||||
object = object.im_func
|
object = object.__func__
|
||||||
|
|
||||||
if name == realname:
|
if name == realname:
|
||||||
title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
|
title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
|
||||||
|
@ -1227,17 +1227,17 @@ class TextDoc(Doc):
|
||||||
note = ''
|
note = ''
|
||||||
skipdocs = 0
|
skipdocs = 0
|
||||||
if inspect.ismethod(object):
|
if inspect.ismethod(object):
|
||||||
imclass = object.im_class
|
imclass = object.__self__.__class__
|
||||||
if cl:
|
if cl:
|
||||||
if imclass is not cl:
|
if imclass is not cl:
|
||||||
note = ' from ' + classname(imclass, mod)
|
note = ' from ' + classname(imclass, mod)
|
||||||
else:
|
else:
|
||||||
if object.im_self is not None:
|
if object.__self__ is not None:
|
||||||
note = ' method of %s instance' % classname(
|
note = ' method of %s instance' % classname(
|
||||||
object.im_self.__class__, mod)
|
object.__self__.__class__, mod)
|
||||||
else:
|
else:
|
||||||
note = ' unbound %s method' % classname(imclass,mod)
|
note = ' unbound %s method' % classname(imclass,mod)
|
||||||
object = object.im_func
|
object = object.__func__
|
||||||
|
|
||||||
if name == realname:
|
if name == realname:
|
||||||
title = self.bold(realname)
|
title = self.bold(realname)
|
||||||
|
|
|
@ -33,6 +33,6 @@ lst = [None] * 1000000
|
||||||
i = 0
|
i = 0
|
||||||
del a
|
del a
|
||||||
while 1:
|
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
|
lst[i] = c.g # consume the free list of instancemethod objects
|
||||||
i += 1
|
i += 1
|
||||||
|
|
|
@ -280,12 +280,12 @@ def test_dir():
|
||||||
|
|
||||||
c = C()
|
c = C()
|
||||||
vereq(interesting(dir(c)), cstuff)
|
vereq(interesting(dir(c)), cstuff)
|
||||||
#verify('im_self' in dir(C.Cmethod))
|
#verify('__self__' in dir(C.Cmethod))
|
||||||
|
|
||||||
c.cdata = 2
|
c.cdata = 2
|
||||||
c.cmethod = lambda self: 0
|
c.cmethod = lambda self: 0
|
||||||
vereq(interesting(dir(c)), cstuff + ['cdata', 'cmethod'])
|
vereq(interesting(dir(c)), cstuff + ['cdata', 'cmethod'])
|
||||||
#verify('im_self' in dir(c.Cmethod))
|
#verify('__self__' in dir(c.Cmethod))
|
||||||
|
|
||||||
class A(C):
|
class A(C):
|
||||||
Adata = 1
|
Adata = 1
|
||||||
|
@ -293,13 +293,13 @@ def test_dir():
|
||||||
|
|
||||||
astuff = ['Adata', 'Amethod'] + cstuff
|
astuff = ['Adata', 'Amethod'] + cstuff
|
||||||
vereq(interesting(dir(A)), astuff)
|
vereq(interesting(dir(A)), astuff)
|
||||||
#verify('im_self' in dir(A.Amethod))
|
#verify('__self__' in dir(A.Amethod))
|
||||||
a = A()
|
a = A()
|
||||||
vereq(interesting(dir(a)), astuff)
|
vereq(interesting(dir(a)), astuff)
|
||||||
a.adata = 42
|
a.adata = 42
|
||||||
a.amethod = lambda self: 3
|
a.amethod = lambda self: 3
|
||||||
vereq(interesting(dir(a)), astuff + ['adata', 'amethod'])
|
vereq(interesting(dir(a)), astuff + ['adata', 'amethod'])
|
||||||
#verify('im_self' in dir(a.Amethod))
|
#verify('__self__' in dir(a.Amethod))
|
||||||
|
|
||||||
# Try a module subclass.
|
# Try a module subclass.
|
||||||
import sys
|
import sys
|
||||||
|
@ -1418,10 +1418,10 @@ def classmethods():
|
||||||
vereq(ff.__get__(0)(42), (int, 42))
|
vereq(ff.__get__(0)(42), (int, 42))
|
||||||
|
|
||||||
# Test super() with classmethods (SF bug 535444)
|
# Test super() with classmethods (SF bug 535444)
|
||||||
veris(C.goo.im_self, C)
|
veris(C.goo.__self__, C)
|
||||||
veris(D.goo.im_self, D)
|
veris(D.goo.__self__, D)
|
||||||
veris(super(D,D).goo.im_self, D)
|
veris(super(D,D).goo.__self__, D)
|
||||||
veris(super(D,d).goo.im_self, D)
|
veris(super(D,d).goo.__self__, D)
|
||||||
vereq(super(D,D).goo(), (D,))
|
vereq(super(D,D).goo(), (D,))
|
||||||
vereq(super(D,d).goo(), (D,))
|
vereq(super(D,d).goo(), (D,))
|
||||||
|
|
||||||
|
@ -1507,7 +1507,7 @@ def classic():
|
||||||
r = repr(E().foo)
|
r = repr(E().foo)
|
||||||
verify(r.startswith("<bound method E.foo "), r)
|
verify(r.startswith("<bound method E.foo "), r)
|
||||||
r = repr(C.foo.__get__(C()))
|
r = repr(C.foo.__get__(C()))
|
||||||
verify(r.startswith("<bound method ?.foo "), r)
|
verify(r.startswith("<bound method "), r)
|
||||||
|
|
||||||
def compattr():
|
def compattr():
|
||||||
if verbose: print("Testing computed attributes...")
|
if verbose: print("Testing computed attributes...")
|
||||||
|
@ -1687,7 +1687,7 @@ def methods():
|
||||||
vereq(d2.goo(), 1)
|
vereq(d2.goo(), 1)
|
||||||
class E(object):
|
class E(object):
|
||||||
foo = C.foo
|
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)))
|
r = repr(C.foo.__get__(C(1)))
|
||||||
verify(r.startswith("<bound method "), r)
|
verify(r.startswith("<bound method "), r)
|
||||||
|
|
||||||
|
@ -1864,17 +1864,6 @@ def recursions():
|
||||||
## raise TestFailed, "expected a RuntimeError for print recursion"
|
## raise TestFailed, "expected a RuntimeError for print recursion"
|
||||||
## sys.stdout = test_stdout
|
## 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():
|
def weakrefs():
|
||||||
if verbose: print("Testing weak references...")
|
if verbose: print("Testing weak references...")
|
||||||
import weakref
|
import weakref
|
||||||
|
|
|
@ -104,11 +104,12 @@ else: raise TestFailed
|
||||||
if f2.a.one != f1.a.one != F.a.one != 11:
|
if f2.a.one != f1.a.one != F.a.one != 11:
|
||||||
raise TestFailed
|
raise TestFailed
|
||||||
|
|
||||||
# im_func may not be a Python method!
|
# __func__ may not be a Python method!
|
||||||
import new
|
import new
|
||||||
F.id = new.instancemethod(id, None, F)
|
F.id = id
|
||||||
|
|
||||||
eff = F()
|
eff = F()
|
||||||
|
eff.id = new.instancemethod(id, eff)
|
||||||
if eff.id() != id(eff):
|
if eff.id() != id(eff):
|
||||||
raise TestFailed
|
raise TestFailed
|
||||||
|
|
||||||
|
@ -296,32 +297,32 @@ def test_func_dict():
|
||||||
verify(f.__dict__ == {'world': 'hello'})
|
verify(f.__dict__ == {'world': 'hello'})
|
||||||
cantset(f, "__dict__", None)
|
cantset(f, "__dict__", None)
|
||||||
|
|
||||||
def test_im_class():
|
def test___self__():
|
||||||
class C:
|
class C:
|
||||||
def foo(self): pass
|
def foo(self): pass
|
||||||
#verify(C.foo.im_class is C)
|
#verify(C.foo.__self__.__class__ is C)
|
||||||
verify(C().foo.im_class is C)
|
verify(C().foo.__self__.__class__ is C)
|
||||||
#cantset(C.foo, "im_class", C)
|
#cantset(C.foo, "__self__.__class__", C)
|
||||||
cantset(C().foo, "im_class", C)
|
cantset(C().foo, "__self__.__class__", C)
|
||||||
|
|
||||||
def test_im_func():
|
def test___func__():
|
||||||
def foo(self): pass
|
def foo(self): pass
|
||||||
class C:
|
class C:
|
||||||
pass
|
pass
|
||||||
C.foo = foo
|
C.foo = foo
|
||||||
#verify(C.foo.im_func is foo)
|
#verify(C.foo.__func__ is foo)
|
||||||
verify(C().foo.im_func is foo)
|
verify(C().foo.__func__ is foo)
|
||||||
#cantset(C.foo, "im_func", foo)
|
#cantset(C.foo, "__func__", foo)
|
||||||
cantset(C().foo, "im_func", foo)
|
cantset(C().foo, "__func__", foo)
|
||||||
|
|
||||||
def test_im_self():
|
def test___self__():
|
||||||
class C:
|
class C:
|
||||||
def foo(self): pass
|
def foo(self): pass
|
||||||
#verify(C.foo.im_self is None)
|
#verify(C.foo.__self__ is None)
|
||||||
c = C()
|
c = C()
|
||||||
#verify(c.foo.im_self is c)
|
#verify(c.foo.__self__ is c)
|
||||||
#cantset(C.foo, "im_self", None)
|
#cantset(C.foo, "__self__", None)
|
||||||
#cantset(c.foo, "im_self", c)
|
#cantset(c.foo, "__self__", c)
|
||||||
|
|
||||||
def test_im_dict():
|
def test_im_dict():
|
||||||
class C:
|
class C:
|
||||||
|
@ -358,9 +359,9 @@ def testmore():
|
||||||
test_func_defaults()
|
test_func_defaults()
|
||||||
test_func_dict()
|
test_func_dict()
|
||||||
# Tests for instance method attributes
|
# Tests for instance method attributes
|
||||||
test_im_class()
|
test___self__()
|
||||||
test_im_func()
|
test___func__()
|
||||||
test_im_self()
|
test___self__()
|
||||||
test_im_dict()
|
test_im_dict()
|
||||||
test_im_doc()
|
test_im_doc()
|
||||||
test_im_name()
|
test_im_name()
|
||||||
|
|
|
@ -25,7 +25,7 @@ class NewTest(unittest.TestCase):
|
||||||
# new.instancemethod()
|
# new.instancemethod()
|
||||||
c = C()
|
c = C()
|
||||||
c.yolks = 3
|
c.yolks = 3
|
||||||
im = new.instancemethod(break_yolks, c, C)
|
im = new.instancemethod(break_yolks, c)
|
||||||
|
|
||||||
self.assertEqual(c.get_yolks(), 3,
|
self.assertEqual(c.get_yolks(), 3,
|
||||||
'Broken call of hand-crafted class instance')
|
'Broken call of hand-crafted class instance')
|
||||||
|
@ -43,7 +43,7 @@ class NewTest(unittest.TestCase):
|
||||||
self.assertEqual(c.get_yolks(), -1)
|
self.assertEqual(c.get_yolks(), -1)
|
||||||
|
|
||||||
# Verify that dangerous instance method creation is forbidden
|
# 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
|
# Verify that instancemethod() doesn't allow keyword args
|
||||||
self.assertRaises(TypeError, new.instancemethod, break_yolks, c, kw=1)
|
self.assertRaises(TypeError, new.instancemethod, break_yolks, c, kw=1)
|
||||||
|
|
|
@ -31,7 +31,7 @@ class HookWatcher:
|
||||||
|
|
||||||
def get_events(self):
|
def get_events(self):
|
||||||
"""Remove calls to add_event()."""
|
"""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
|
self.frames = None
|
||||||
|
|
||||||
return [item for item in self.events if item[2] not in disallowed]
|
return [item for item in self.events if item[2] not in disallowed]
|
||||||
|
|
|
@ -67,7 +67,7 @@ class PyclbrTest(TestCase):
|
||||||
if isinstance(obj, MethodType):
|
if isinstance(obj, MethodType):
|
||||||
# could be a classmethod
|
# could be a classmethod
|
||||||
if (not isinstance(classdict[name], ClassMethodType) or
|
if (not isinstance(classdict[name], ClassMethodType) or
|
||||||
obj.im_self is not oclass):
|
obj.__self__ is not oclass):
|
||||||
return False
|
return False
|
||||||
elif not isinstance(obj, FunctionType):
|
elif not isinstance(obj, FunctionType):
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -44,6 +44,12 @@ Core and Builtins
|
||||||
- Renamed structmember.h WRITE_RESTRICTED to PY_WRITE_RESTRICTED to work
|
- Renamed structmember.h WRITE_RESTRICTED to PY_WRITE_RESTRICTED to work
|
||||||
around a name clash with VS 2008 on Windows.
|
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
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -26,33 +26,25 @@ PyMethod_Self(PyObject *im)
|
||||||
return ((PyMethodObject *)im)->im_self;
|
return ((PyMethodObject *)im)->im_self;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
/* Method objects are used for bound instance methods returned by
|
||||||
PyMethod_Class(PyObject *im)
|
instancename.methodname. ClassName.methodname returns an ordinary
|
||||||
{
|
function.
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static PyMethodObject *free_list;
|
static PyMethodObject *free_list;
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyMethod_New(PyObject *func, PyObject *self, PyObject *klass)
|
PyMethod_New(PyObject *func, PyObject *self)
|
||||||
{
|
{
|
||||||
register PyMethodObject *im;
|
register PyMethodObject *im;
|
||||||
if (!PyCallable_Check(func)) {
|
if (!PyCallable_Check(func)) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (self == NULL) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
im = free_list;
|
im = free_list;
|
||||||
if (im != NULL) {
|
if (im != NULL) {
|
||||||
free_list = (PyMethodObject *)(im->im_self);
|
free_list = (PyMethodObject *)(im->im_self);
|
||||||
|
@ -68,25 +60,21 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *klass)
|
||||||
im->im_func = func;
|
im->im_func = func;
|
||||||
Py_XINCREF(self);
|
Py_XINCREF(self);
|
||||||
im->im_self = self;
|
im->im_self = self;
|
||||||
Py_XINCREF(klass);
|
|
||||||
im->im_class = klass;
|
|
||||||
_PyObject_GC_TRACK(im);
|
_PyObject_GC_TRACK(im);
|
||||||
return (PyObject *)im;
|
return (PyObject *)im;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Descriptors for PyMethod attributes */
|
/* 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)
|
#define OFF(x) offsetof(PyMethodObject, x)
|
||||||
|
|
||||||
static PyMemberDef method_memberlist[] = {
|
static PyMemberDef method_memberlist[] = {
|
||||||
{"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED,
|
{"__func__", T_OBJECT, OFF(im_func), READONLY|RESTRICTED,
|
||||||
"the class associated with a method"},
|
|
||||||
{"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED,
|
|
||||||
"the function (or other callable) implementing a method"},
|
"the function (or other callable) implementing a method"},
|
||||||
{"im_self", T_OBJECT, OFF(im_self), READONLY|RESTRICTED,
|
{"__self__", T_OBJECT, OFF(im_self), READONLY|RESTRICTED,
|
||||||
"the instance to which a method is bound; None for unbound methods"},
|
"the instance to which a method is bound"},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,7 +129,7 @@ method_getattro(PyObject *obj, PyObject *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(method_doc,
|
PyDoc_STRVAR(method_doc,
|
||||||
"method(function, instance, class)\n\
|
"method(function, instance)\n\
|
||||||
\n\
|
\n\
|
||||||
Create an instance method object.");
|
Create an instance method object.");
|
||||||
|
|
||||||
|
@ -150,27 +138,24 @@ method_new(PyTypeObject* type, PyObject* args, PyObject *kw)
|
||||||
{
|
{
|
||||||
PyObject *func;
|
PyObject *func;
|
||||||
PyObject *self;
|
PyObject *self;
|
||||||
PyObject *classObj = NULL;
|
|
||||||
|
|
||||||
if (!_PyArg_NoKeywords("instancemethod", kw))
|
if (!_PyArg_NoKeywords("instancemethod", kw))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!PyArg_UnpackTuple(args, "method", 2, 3,
|
if (!PyArg_UnpackTuple(args, "method", 2, 3,
|
||||||
&func, &self, &classObj))
|
&func, &self))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!PyCallable_Check(func)) {
|
if (!PyCallable_Check(func)) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"first argument must be callable");
|
"first argument must be callable");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (self == Py_None)
|
if (self == NULL || self == Py_None) {
|
||||||
self = NULL;
|
|
||||||
if (self == NULL && classObj == NULL) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"unbound methods must have non-NULL im_class");
|
"self must not be None");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PyMethod_New(func, self, classObj);
|
return PyMethod_New(func, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -181,7 +166,6 @@ method_dealloc(register PyMethodObject *im)
|
||||||
PyObject_ClearWeakRefs((PyObject *)im);
|
PyObject_ClearWeakRefs((PyObject *)im);
|
||||||
Py_DECREF(im->im_func);
|
Py_DECREF(im->im_func);
|
||||||
Py_XDECREF(im->im_self);
|
Py_XDECREF(im->im_self);
|
||||||
Py_XDECREF(im->im_class);
|
|
||||||
im->im_self = (PyObject *)free_list;
|
im->im_self = (PyObject *)free_list;
|
||||||
free_list = im;
|
free_list = im;
|
||||||
}
|
}
|
||||||
|
@ -225,10 +209,15 @@ method_repr(PyMethodObject *a)
|
||||||
{
|
{
|
||||||
PyObject *self = a->im_self;
|
PyObject *self = a->im_self;
|
||||||
PyObject *func = a->im_func;
|
PyObject *func = a->im_func;
|
||||||
PyObject *klass = a->im_class;
|
PyObject *klass = (PyObject*)Py_Type(self);
|
||||||
PyObject *funcname = NULL ,*klassname = NULL, *result = NULL;
|
PyObject *funcname = NULL ,*klassname = NULL, *result = NULL;
|
||||||
char *defname = "?";
|
char *defname = "?";
|
||||||
|
|
||||||
|
if (self == NULL) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
funcname = PyObject_GetAttrString(func, "__name__");
|
funcname = PyObject_GetAttrString(func, "__name__");
|
||||||
if (funcname == NULL) {
|
if (funcname == NULL) {
|
||||||
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||||
|
@ -239,6 +228,7 @@ method_repr(PyMethodObject *a)
|
||||||
Py_DECREF(funcname);
|
Py_DECREF(funcname);
|
||||||
funcname = NULL;
|
funcname = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (klass == NULL)
|
if (klass == NULL)
|
||||||
klassname = NULL;
|
klassname = NULL;
|
||||||
else {
|
else {
|
||||||
|
@ -253,16 +243,12 @@ method_repr(PyMethodObject *a)
|
||||||
klassname = NULL;
|
klassname = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self == NULL)
|
|
||||||
result = PyUnicode_FromFormat("<unbound method %V.%V>",
|
|
||||||
klassname, defname,
|
|
||||||
funcname, defname);
|
|
||||||
else {
|
|
||||||
/* XXX Shouldn't use repr()/%R here! */
|
/* XXX Shouldn't use repr()/%R here! */
|
||||||
result = PyUnicode_FromFormat("<bound method %V.%V of %R>",
|
result = PyUnicode_FromFormat("<bound method %V.%V of %R>",
|
||||||
klassname, defname,
|
klassname, defname,
|
||||||
funcname, defname, self);
|
funcname, defname, self);
|
||||||
}
|
|
||||||
Py_XDECREF(funcname);
|
Py_XDECREF(funcname);
|
||||||
Py_XDECREF(klassname);
|
Py_XDECREF(klassname);
|
||||||
return result;
|
return result;
|
||||||
|
@ -292,93 +278,20 @@ method_traverse(PyMethodObject *im, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
Py_VISIT(im->im_func);
|
Py_VISIT(im->im_func);
|
||||||
Py_VISIT(im->im_self);
|
Py_VISIT(im->im_self);
|
||||||
Py_VISIT(im->im_class);
|
|
||||||
return 0;
|
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 *
|
static PyObject *
|
||||||
method_call(PyObject *func, PyObject *arg, PyObject *kw)
|
method_call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||||
{
|
{
|
||||||
PyObject *self = PyMethod_GET_SELF(func);
|
PyObject *self = PyMethod_GET_SELF(func);
|
||||||
PyObject *klass = PyMethod_GET_CLASS(func);
|
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
func = PyMethod_GET_FUNCTION(func);
|
func = PyMethod_GET_FUNCTION(func);
|
||||||
if (self == NULL) {
|
if (self == NULL) {
|
||||||
/* Unbound methods must be called with an instance of
|
PyErr_BadInternalCall();
|
||||||
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;
|
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);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
Py_ssize_t argcount = PyTuple_Size(arg);
|
Py_ssize_t argcount = PyTuple_Size(arg);
|
||||||
PyObject *newarg = PyTuple_New(argcount + 1);
|
PyObject *newarg = PyTuple_New(argcount + 1);
|
||||||
|
@ -402,27 +315,15 @@ method_call(PyObject *func, PyObject *arg, PyObject *kw)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls)
|
method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls)
|
||||||
{
|
{
|
||||||
/* Don't rebind an already bound method, or an unbound method
|
/* Don't rebind an already bound method of a class that's not a base
|
||||||
of a class that's not a base class of cls. */
|
class of cls. */
|
||||||
|
|
||||||
if (PyMethod_GET_SELF(meth) != NULL) {
|
if (PyMethod_GET_SELF(meth) != NULL) {
|
||||||
/* Already bound */
|
/* Already bound */
|
||||||
Py_INCREF(meth);
|
Py_INCREF(meth);
|
||||||
return 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 */
|
/* Bind it to obj */
|
||||||
return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj, cls);
|
return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTypeObject PyMethod_Type = {
|
PyTypeObject PyMethod_Type = {
|
||||||
|
|
|
@ -647,7 +647,7 @@ func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
|
||||||
Py_INCREF(func);
|
Py_INCREF(func);
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
return PyMethod_New(func, obj, type);
|
return PyMethod_New(func, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTypeObject PyFunction_Type = {
|
PyTypeObject PyFunction_Type = {
|
||||||
|
@ -751,8 +751,7 @@ cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||||
}
|
}
|
||||||
if (type == NULL)
|
if (type == NULL)
|
||||||
type = (PyObject *)(Py_Type(obj));
|
type = (PyObject *)(Py_Type(obj));
|
||||||
return PyMethod_New(cm->cm_callable,
|
return PyMethod_New(cm->cm_callable, type);
|
||||||
type, (PyObject *)(Py_Type(type)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
Loading…
Reference in New Issue