classification
Title: super instances don't support item assignment
Type: Stage:
Components: Interpreter Core Versions:
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: fdrake, gvanrossum, rhettinger
Priority: normal Keywords:

Created on 2003-09-12 20:10 by fdrake, last changed 2004-08-17 02:22 by rhettinger. This issue is now closed.

Files
File name Uploaded Description Edit
abstract2.diff rhettinger, 2003-09-14 02:07 Diff for Objects\abstract.c using &PySuper_Type
Messages (6)
msg18148 - (view) Author: Fred L. Drake, Jr. (fdrake) (Python committer) Date: 2003-09-12 20:10
This snippet produces a TypeError in Python 2.2.3, 2.3,
and CVS:

class C(object):
    def __setitem__(self, name, value):
        print (name, value)

class D(C):
    def __setitem__(self, name, value):
        super(D, self)[name] = value

d = D()
d['foo'] = 'bar'

Here's the traceback:

Traceback (most recent call last):
  File "/home/fdrake/tmp/setitem.py", line 10, in ?
    d['foo'] = 'bar'
  File "/home/fdrake/tmp/setitem.py", line 7, in
__setitem__
    super(D, self)[name] = value
TypeError: object does not support item assignment

The problem appears to be that the item assignment
isn't getting mapped to the __setitem__ of the base
class, so this is probably somewhere deep in
Objects/typeobject.c.
msg18149 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2003-09-13 06:50
Logged In: YES 
user_id=80475

This one is tough.  

All of super's magic happens with descriptors upon attribute 
lookup.  The example above will work fine if the call were 
written as:  "super(D, self).__setitem__(name)".

However, when written as "super(D, self)[name]", ceval.c 
triggers a STORE_SUBSCR opcode which calls 
PyObject_SetItem which in turns looks directly at the super 
object's type table (and finding nothing).  Nowhere in this 
process is an attribute lookup called or a descriptor invoked.

The current implementation waits until attribute binding time 
to search the bases.  Hence, at the time the super object is 
created, it doesn't know enough information to fill out its 
table about which methods will be available.  Consequently, 
direct table probes will fail.

To make a general purpose fix would be a mess and involves 
changing the semantics of super to do its base search at the 
time the super object is created and to fillout its table with 
the appropriate methods.  Unfortunately, any dynamic 
changes to the methods in the base object would *not* get 
reflected at lookup.

There may be a reasonable special purpose fix.  Fill-out the 
entire superobject table with custom methods that trigger an 
attribute lookup.  For instance, fillout the sq_ass_item slot 
with a function that calls self.__setitem__ which will trigger 
the attribute search.  Even this approach has problems 
because the super object has no way of knowing in advance 
whether sq_ass_item or mp_ass_subscript is the appropriate 
method for the object being referred to (is it a mapping or a 
sequence?).

I recommend punting on this one and documenting that 
direct syntax manipulation of super objects is not defined 
and the super().__special_method__ format be used instead.
Perhaps, all of super's unfilled slots can be filled with a 
placeholder method that emits an explanatory error message.
msg18150 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2003-09-13 23:19
Logged In: YES 
user_id=80475

Okay, let's apply the two-step problem solving approach.  
First, declare the problem impossible to solve.  Then, propose 
a solution ;-)

The attached patch is a proof-of-concept.  It teaches 
PyObject_SetItem to use an attribute lookup for super 
objects whenever a direct table lookup fails.

If the approach is approved, the final version of the patch 
should also address PyObject_GetItem and other ways that 
the attribute lookup mechanism can be bypassed. Also, the 
test for super can be improved by adding PySuper_Check() 
to the typeobject.c API.

Of course, there is also the question as to whether fixing this 
is a bug or a feature.  It does enable a whole set of programs 
to run under Py2.3.1 and Py2.2.4 that would not run under 
Py2.3.0 and Py2.2.3.
msg18151 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2003-09-16 04:48
Logged In: YES 
user_id=80475

Referring to Guido for pronouncement.

I've been thinking that this one could be left alone and just 
document that super objects only do their magic upon 
explicit attribute lookup.

Otherwise, fixing it completely involves combing Python for 
every place that directly calls functions from the slots table, 
and then adding a followup call using attribute lookup if the 
slot is empty.

When it comes to functions like repr(obj), I think we want 
the super object to identify itself rather than forwarding the 
call to the target object's __repr__() method.

The downside of leaving it alone is that it breaks the 
symmetry between obj[k] and obj.__getitem__[k].

msg18152 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2004-03-20 22:56
Logged In: YES 
user_id=6380

This should be coded as Raymond originally recommended:
super(D, self).__setitem__(name, value).

Raymond, can you update the docs?
msg18153 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2004-08-17 02:22
Logged In: YES 
user_id=80475

Documented in Doc/lib/libfuncs.tex 1.173.
History
Date User Action Args
2003-09-12 20:10:43fdrakecreate