[Python-Dev] NotImplemented reaching top-level

M.-A. Lemburg mal at egenix.com
Wed Dec 28 21:56:43 CET 2005


Armin Rigo wrote:
> Hi Facundo,
> 
> On Sat, Dec 24, 2005 at 02:31:19PM -0300, Facundo Batista wrote:
>>>>> d += 1.2
>>>>> d
>> NotImplemented
> 
> The situation appears to be a mess.  Some combinations of specific
> operators fail to convert NotImplemented to a TypeError, depending on
> old- or new-style-class-ness, although this is clearly a bug (e.g. in an
> example like yours but using -= instead of +=, we get the correct
> TypeError.)
> 
> Obviously, we need to write some comprehensive tests about this.  But
> now I just found out that the old, still-pending SF bug #847024 about
> A()*5 in new-style classes hasn't been given any attention; my theory is
> that nobody fully understands the convoluted code paths of abstract.c
> any more :-(

The PEP documenting the coercion logic has complete tables
for what should happen:

http://www.python.org/peps/pep-0208.html

Looking at the code in abstract.c the above problem appears
to be related to the special cases applied to += and *=
in case both operands cannot deal with the type combination.

In such a case, a check is done whether the operation could
be interpreted as sequence operation (concat or repeat) and
then delegated to the appropriate handlers.

But then again, looking in typeobject.c, the following code
could be the cause for leaking a NotImplemented singleton
reference:

#define SLOT1BINFULL(FUNCNAME, TESTFUNC, SLOTNAME, OPSTR, ROPSTR) \
static PyObject * \
FUNCNAME(PyObject *self, PyObject *other) \
{ \
	static PyObject *cache_str, *rcache_str; \
	int do_other = self->ob_type != other->ob_type && \
	    other->ob_type->tp_as_number != NULL && \
	    other->ob_type->tp_as_number->SLOTNAME == TESTFUNC; \
	if (self->ob_type->tp_as_number != NULL && \
	    self->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \
		PyObject *r; \
		if (do_other && \
		    PyType_IsSubtype(other->ob_type, self->ob_type) && \
		    method_is_overloaded(self, other, ROPSTR)) { \
			r = call_maybe( \
				other, ROPSTR, &rcache_str, "(O)", self); \
			if (r != Py_NotImplemented) \
				return r; \
			Py_DECREF(r); \
			do_other = 0; \
		} \
		r = call_maybe( \
			self, OPSTR, &cache_str, "(O)", other); \
		if (r != Py_NotImplemented || \
		    other->ob_type == self->ob_type) \
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If both types are of the same type, then a NotImplemented returng
value would be returned.

			return r; \
		Py_DECREF(r); \
	} \
	if (do_other) { \
		return call_maybe( \
			other, ROPSTR, &rcache_str, "(O)", self); \
	} \
	Py_INCREF(Py_NotImplemented); \
	return Py_NotImplemented; \
}

Strange enough, the SLOT1BINFULL macro is not used by the
inplace concat or repeat slots...

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Dec 28 2005)
>>> Python/Zope Consulting and Support ...        http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________

::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::


More information about the Python-Dev mailing list