Is this a super bug?

Bjorn Pettersen BPettersen at NAREX.com
Sun Apr 20 00:07:30 EDT 2003


> From: Terry Reedy [mailto:tjreedy at udel.edu] 
> 
> "Bjorn Pettersen" <BPettersen at NAREX.com> wrote in message
>
> >>> class ff(str):
> ...    def foo(self):
[...]
> ...      print 'super(ff, self)[0]', super(ff, self)[0]
> ...
> >>> f = ff('asdf')
> >>> f.foo()
> super(ff, self)[0]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "<stdin>", line 5, in foo
> TypeError: unsubscriptable object
> ----------
> I suspect that printing type(super(ff,self)) might answer your
> question.

I'm afraid not :-)  I allready did that, and from what I can tell, this
is the sequence that "should" happen:

1  super(ff, f)[0]  # f == self
2  superinst(type:<class ff>, obj:f)[0]
3  si.__getitem__(0)
4    si.__getattr__('__getitem__')
5    .. return str.__dict__['__getitem__'].__get__(f)
6    boundmethod(str.__getitem__, f)
7  bmeth(0)
8   'a'

well, the transition from 3 to 4 doesn't happen which surprised me a
little. What surprised me more was that I couldn't get __getattribute__
to be called either (neither in the class or its metaclass... I've only
got 2.3a2, and I read a note about this not working before a4. Is this
what is happening? If not, the only other reason I could see would be
from the refMan 5.3.2, "The primary must evaluate to an object of a
sequence or mapping type."  If that is the case, then I still think it's
a super bug, i.e. there is no reason super should assume that it's not
"going to be" a sequence, in fact the direct superclass of ff _is_ a
sequence. To fix it simply add:

  def __getitem__(self, v):
      m = self.__getattr__('__getitem__')
      return m(v)

to the definition of super. This will change the exception to
AttributeError if a superclass isn't a sequence. To keep the current
semantics, add the lookup to only instances that are sequence proxies
(example below, refactor between __getattr__ as desired...)

-- bjorn

class Super(object):
    def __init__(self, type, obj=None):
        self.__type__ = type
        self.__obj__ = obj

        if isinstance(self.__obj__, self.__type__):
            starttype = self.__obj__.__class__
        else:
            starttype = self.__obj__
        mro = iter(starttype.__mro__)
           
        for cls in mro:             
            if cls is self.__type__:
                break               

        for cls in mro:
            if '__getitem__' in cls.__dict__:
                def getitem(v):
                    m = self.__getattr__('__getitem__')
                    return m(v)
                self.__possibleGetitem = getitem
                break

    def __possibleGetitem(self, v):
        raise TypeError("unindexable object")

    def __getitem__(self, v):
        return self.__possibleGetitem(v)





More information about the Python-list mailing list