Help with super()

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • David Hirschfield

    #1

    Help with super()

    I'm having trouble with the new descriptor-based mechanisms like super()
    and property() stemming, most likely, from my lack of knowledge about
    how they work.

    Here's an example that's giving me trouble, I know it won't work, but it
    illustrates what I want to do:

    class A(object):
    _v = [1,2,3]

    def _getv(self):
    if self.__class__ == A:
    return self._v
    return super(self.__cl ass__,self).v + self._v

    v = property(_getv)


    class B(A):
    _v = [4,5,6]

    b = B()
    print b.v

    What I want is for b.v to give me back [1,2,3,4,5,6], but this example
    gets into a recursive infinite loop, since super(B,self).v is still
    B._getv(), not A._getv().

    Is there a way to get what I'm after using super()?

    The idea is that I could have a chain of subclasses which only need to
    redefine _v, and getting the value of v as a property would give me back
    the full chain of _v values for that class and all its ancestor classes.

    Thanks in advance,
    -David

    --
    Presenting:
    mediocre nebula.

  • Mike Meyer

    #2
    Re: Help with super()

    David Hirschfield <davidh@ilm.com > writes:[color=blue]
    > I'm having trouble with the new descriptor-based mechanisms like
    > super() and property() stemming, most likely, from my lack of
    > knowledge about how they work.
    >
    > Here's an example that's giving me trouble, I know it won't work, but
    > it illustrates what I want to do:
    >
    > class A(object):
    > _v = [1,2,3]
    > def _getv(self):
    > if self.__class__ == A:
    > return self._v
    > return super(self.__cl ass__,self).v + self._v
    >
    > v = property(_getv)
    >
    >
    > class B(A):
    > _v = [4,5,6]
    > b = B()
    > print b.v
    >
    > What I want is for b.v to give me back [1,2,3,4,5,6], but this example
    > gets into a recursive infinite loop, since super(B,self).v is still
    > B._getv(), not A._getv().
    >
    > Is there a way to get what I'm after using super()?[/color]

    Yes. Call super with A as the first argument, not self.__class__.

    That's twice in the last little bit I've seen someone incorrectly use
    self.__class__ instead of using the class name. Is there bogus
    documentation somewhere that's recommending this?

    <mike
    --
    Mike Meyer <mwm@mired.or g> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.

    Comment

    • David Hirschfield

      #3
      Re: Help with super()

      I tried that and super(B,self), but neither works.

      Using super(A,self) in the _getv(self) method doesn't work, since the
      super() of A is "object" and that doesn't have the v property at all.
      Not sure why you say that using self.__class__ is wrong as the first
      argument to super(), it should be the same as using the class name
      itself - both will result in <class blah.B> or whetever self is an
      instance of.

      I still don't see a way to accomplish my original goal, but any other
      suggestions you might have would be appreciated.
      Thanks,
      -David

      Mike Meyer wrote:
      [color=blue]
      >David Hirschfield <davidh@ilm.com > writes:
      >
      >[color=green]
      >>I'm having trouble with the new descriptor-based mechanisms like
      >>super() and property() stemming, most likely, from my lack of
      >>knowledge about how they work.
      >>
      >>Here's an example that's giving me trouble, I know it won't work, but
      >>it illustrates what I want to do:
      >>
      >>class A(object):
      >> _v = [1,2,3]
      >> def _getv(self):
      >> if self.__class__ == A:
      >> return self._v
      >> return super(self.__cl ass__,self).v + self._v
      >>
      >> v = property(_getv)
      >>
      >>
      >>class B(A):
      >> _v = [4,5,6]
      >> b = B()
      >>print b.v
      >>
      >>What I want is for b.v to give me back [1,2,3,4,5,6], but this example
      >>gets into a recursive infinite loop, since super(B,self).v is still
      >>B._getv(), not A._getv().
      >>
      >>Is there a way to get what I'm after using super()?
      >>
      >>[/color]
      >
      >Yes. Call super with A as the first argument, not self.__class__.
      >
      >That's twice in the last little bit I've seen someone incorrectly use
      >self.__class __ instead of using the class name. Is there bogus
      >documentatio n somewhere that's recommending this?
      >
      > <mike
      >
      >[/color]

      --
      Presenting:
      mediocre nebula.

      Comment

      • David Hirschfield

        #4
        Re: Help with super()

        Good point, I did notice that.

        My example is total junk, actually. Now that I look at it, it isn't at
        all possible to do what I'm after this way, since _getv() is never going
        to be looking at class A's _v value.

        So, the larger question is how to do anything that resembles what I
        want, which is to have a chain of subclasses with a single attribute
        that each subclass can define as it wishes to, but with the ability to
        get the combined value from all the ancestors down to the current
        subclass I access that attribute from.

        Does that make any sense?

        Something like (and this is totally made-up pseudo-code):

        class A:
        v = [1,2]

        class B(A):
        v = [2,3]

        class C(B):
        v = [4,5]

        c = C()
        c.getv() ==> [1,2,2,3,4,5]

        -Dave

        Paul McNett wrote:
        [color=blue]
        > David Hirschfield wrote:
        >[color=green]
        >> I tried that and super(B,self), but neither works.
        >>
        >> Using super(A,self) in the _getv(self) method doesn't work, since the
        >> super() of A is "object" and that doesn't have the v property at all.
        >> Not sure why you say that using self.__class__ is wrong as the first
        >> argument to super(), it should be the same as using the class name
        >> itself - both will result in <class blah.B> or whetever self is an
        >> instance of.
        >>
        >> I still don't see a way to accomplish my original goal, but any other
        >> suggestions you might have would be appreciated.[/color]
        >
        >
        > Your basic problem is that property fset(), fget() and friends are
        > defined at the class level, not at the instance level. So if you want
        > to override the setter of a property in a subclass, you pretty much
        > have to redefine the property in that subclass. And therefore, you
        > also have to redefine the getter of the property as well. There is no
        > easy way to "subclass" property getters and setters.
        >
        > But, there's another problem with your example code as well. You
        > appear to assume that self._v is going to refer to the _v defined in
        > that class. But take a look at this:
        >
        > class A(object):
        > _v = [1,2,3]
        >
        > def _getv(self):
        > print self._v ## hey, look, I'm [4,5,6]!!!
        > v = property(_getv)
        >
        >
        > class B(A):
        > _v = [4,5,6]
        >
        > b = B()
        >
        > print b.v
        >
        >[/color]

        --
        Presenting:
        mediocre nebula.

        Comment

        • Paul McNett

          #5
          Re: Help with super()

          David Hirschfield wrote:[color=blue]
          > So, the larger question is how to do anything that resembles what I
          > want, which is to have a chain of subclasses with a single attribute
          > that each subclass can define as it wishes to, but with the ability to
          > get the combined value from all the ancestors down to the current
          > subclass I access that attribute from.
          >
          > Does that make any sense?[/color]

          Yes, it makes sense. The trick is to not query the values using self, but to ask
          the class definitions for the attribute. See my second message that gives an
          example, climbing the __mro__ tree backwards.


          --
          Paul McNett

          PEJUANGJITU hadir sebagai agen toto dengan situs togel online yang terpercaya sehingga menjadikan kami PEJUANG JITU sebagai website dengan pencarian terbanyak di 2026 ini.


          Comment

          • Paul McNett

            #6
            Re: Help with super()

            David Hirschfield wrote:[color=blue]
            > I tried that and super(B,self), but neither works.
            >
            > Using super(A,self) in the _getv(self) method doesn't work, since the
            > super() of A is "object" and that doesn't have the v property at all.
            > Not sure why you say that using self.__class__ is wrong as the first
            > argument to super(), it should be the same as using the class name
            > itself - both will result in <class blah.B> or whetever self is an
            > instance of.
            >
            > I still don't see a way to accomplish my original goal, but any other
            > suggestions you might have would be appreciated.[/color]

            Your basic problem is that property fset(), fget() and friends are defined at
            the class level, not at the instance level. So if you want to override the
            setter of a property in a subclass, you pretty much have to redefine the
            property in that subclass. And therefore, you also have to redefine the getter
            of the property as well. There is no easy way to "subclass" property getters and
            setters.

            But, there's another problem with your example code as well. You appear to
            assume that self._v is going to refer to the _v defined in that class. But take
            a look at this:

            class A(object):
            _v = [1,2,3]

            def _getv(self):
            print self._v ## hey, look, I'm [4,5,6]!!!
            v = property(_getv)


            class B(A):
            _v = [4,5,6]

            b = B()

            print b.v


            --
            Paul McNett

            PEJUANGJITU hadir sebagai agen toto dengan situs togel online yang terpercaya sehingga menjadikan kami PEJUANG JITU sebagai website dengan pencarian terbanyak di 2026 ini.


            Comment

            • Steven Bethard

              #7
              Re: Help with super()

              David Hirschfield wrote:[color=blue]
              > Here's an example that's giving me trouble, I know it won't work, but it
              > illustrates what I want to do:
              >
              > class A(object):
              > _v = [1,2,3]
              > def _getv(self):
              > if self.__class__ == A:
              > return self._v
              > return super(self.__cl ass__,self).v + self._v
              >
              > v = property(_getv)
              >
              > class B(A):
              > _v = [4,5,6]
              > b = B()
              > print b.v
              >
              > What I want is for b.v to give me back [1,2,3,4,5,6], but this example
              > gets into a recursive infinite loop, since super(B,self).v is still
              > B._getv(), not A._getv().[/color]

              You don't actually need to use properties here if you don't want to --
              the Class.v value can be calculated just once, at the time the class
              statement is executed:
              [color=blue][color=green][color=darkred]
              >>> class A(object):[/color][/color][/color]
              .... class __metaclass__(t ype):
              .... def __init__(cls, name, bases, classdict):
              .... superclass = cls.mro()[1]
              .... if superclass is object:
              .... v = []
              .... else:
              .... v = list(superclass .v)
              .... if 'v' in classdict:
              .... v.extend(cls.v)
              .... cls.v = v
              .... v = [1, 2, 3]
              ....[color=blue][color=green][color=darkred]
              >>> class B(A):[/color][/color][/color]
              .... v = [4, 5, 6]
              ....[color=blue][color=green][color=darkred]
              >>> class C(B):[/color][/color][/color]
              .... pass
              ....[color=blue][color=green][color=darkred]
              >>> class D(C):[/color][/color][/color]
              .... v = [7, 8, 9]
              ....[color=blue][color=green][color=darkred]
              >>> A.v[/color][/color][/color]
              [1, 2, 3][color=blue][color=green][color=darkred]
              >>> B.v[/color][/color][/color]
              [1, 2, 3, 4, 5, 6][color=blue][color=green][color=darkred]
              >>> C.v[/color][/color][/color]
              [1, 2, 3, 4, 5, 6][color=blue][color=green][color=darkred]
              >>> D.v[/color][/color][/color]
              [1, 2, 3, 4, 5, 6, 7, 8, 9][color=blue][color=green][color=darkred]
              >>> B.v is C.v[/color][/color][/color]
              False

              Note that A.__metaclass__ .__init__ is called when the A, B, C and D
              class statements are executed. This code simply looks at the superclass
              of class being created, and creates the appropriate v list.

              Note that this approach means that you only create the lists once,
              instead of creating them each time your getv() method is called.
              However, if the list in a superclass changes, the subclass lists will
              not be automatically updated.

              HTH,

              STeVe

              Comment

              Working...