overriding method that returns base class object

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stuart McGraw

    overriding method that returns base class object

    I have a class A from a third party that I cannot change
    and is implemented in C. I derive my own class B from A
    and add a couple new methods and override a method. The
    problem is that A has a method (call it A.f() ) that creates
    and returns a new A object. I need B.f() to return a B
    object derived from A.f(). What is the best way to make
    that happen?

  • Peter Hansen

    #2
    Re: overriding method that returns base class object

    Stuart McGraw wrote:[color=blue]
    >
    > I have a class A from a third party that I cannot change
    > and is implemented in C. I derive my own class B from A
    > and add a couple new methods and override a method. The
    > problem is that A has a method (call it A.f() ) that creates
    > and returns a new A object. I need B.f() to return a B
    > object derived from A.f(). What is the best way to make
    > that happen?[/color]

    If I understand this correctly, it has nothing to do with the
    fact that the parent class is implemented in C and you just
    need to know a little uncommon syntax:

    class A:
    def f(self):
    return A()

    class B(A):
    def f(self):
    obj = A.f(self)
    # do whatever you want to obj here
    return obj

    The key is what you mean by "a B object derived from A.f()". If
    by derived you mean something to do with _inheritance_, then
    either you don't understand inheritance or you weren't clear what
    you wanted.

    If you just mean you want B's f() to do something special to the
    A object that A.f() returns, then the above code should let you
    do that properly...

    -Peter

    Comment

    • Stuart McGraw

      #3
      Re: overriding method that returns base class object

      Sorry, you are right, I wasn't clear. I mean B inherits from
      A. Here is what I am trying to do...

      Class A has a method A.a() that returns an A. I want a
      identical class but with an additional property .newprop
      and method .b() And I want .a() to return a B, not an A.

      class B (A):
      def __init__(self, *args, **kwds):
      A.__init__(self , *args, **kwds)
      self.newprop = 99
      def a(self):
      x = A.a(self) # x is an A
      x.__class__ = B
      return x # I want x to be a B, i.e have b() and .newprop.
      def b(self):
      ...something...

      Yes, I know this is bogus. But I am not sure what
      I should be doing. And to correct what I originally
      posted, A is implented in python (but I still can't
      change it for administrative reasons), but it's properties
      are declared with "__slots__ = [...]" if that makes a
      difference. This is all in Python 2.3.3.


      "Peter Hansen" <peter@engcorp. com> wrote in message news:4031481B.9 0B31C73@engcorp .com...[color=blue]
      > Stuart McGraw wrote:[color=green]
      > >
      > > I have a class A from a third party that I cannot change
      > > and is implemented in C. I derive my own class B from A
      > > and add a couple new methods and override a method. The
      > > problem is that A has a method (call it A.f() ) that creates
      > > and returns a new A object. I need B.f() to return a B
      > > object derived from A.f(). What is the best way to make
      > > that happen?[/color]
      >
      > If I understand this correctly, it has nothing to do with the
      > fact that the parent class is implemented in C and you just
      > need to know a little uncommon syntax:
      >
      > class A:
      > def f(self):
      > return A()
      > se
      > class B(A):
      > def f(self):
      > obj = A.f(self)
      > # do whatever you want to obj here
      > return obj
      >
      > The key is what you mean by "a B object derived from A.f()". If
      > by derived you mean something to do with _inheritance_, then
      > either you don't understand inheritance or you weren't clear what
      > you wanted.
      >
      > If you just mean you want B's f() to do something special to the
      > A object that A.f() returns, then the above code should let you
      > do that properly...
      >
      > -Peter[/color]

      Comment

      • Aahz

        #4
        Re: overriding method that returns base class object

        In article <40315037$0$199 $75868355@news. frii.net>,
        Stuart McGraw <smcg4191@frii. RemoveThisToRep ly.com> wrote:[color=blue]
        >
        >Class A has a method A.a() that returns an A. I want a
        >identical class but with an additional property .newprop
        >and method .b() And I want .a() to return a B, not an A.
        >
        > class B (A):
        > def __init__(self, *args, **kwds):
        > A.__init__(self , *args, **kwds)
        > self.newprop = 99
        > def a(self):
        > x = A.a(self) # x is an A
        > x.__class__ = B
        > return x # I want x to be a B, i.e have b() and .newprop.
        > def b(self):
        > ...something...
        >
        >Yes, I know this is bogus. But I am not sure what I should be doing.
        >And to correct what I originally posted, A is implented in python
        >(but I still can't change it for administrative reasons), but it's
        >properties are declared with "__slots__ = [...]" if that makes a
        >difference. This is all in Python 2.3.3.[/color]

        class A:
        def a(self):
        return self.__class__( )
        --
        Aahz (aahz@pythoncra ft.com) <*> http://www.pythoncraft.com/

        "Argue for your limitations, and sure enough they're yours." --Richard Bach

        Comment

        • Scott David Daniels

          #5
          Re: overriding method that returns base class object

          Stuart McGraw wrote:
          [color=blue]
          > Sorry, you are right, I wasn't clear. I mean B inherits from
          > A. Here is what I am trying to do...
          >
          > Class A has a method A.a() that returns an A. I want a
          > identical class but with an additional property .newprop
          > and method .b() And I want .a() to return a B, not an A.
          >
          > class B (A):
          > def __init__(self, *args, **kwds):
          > A.__init__(self , *args, **kwds)
          > self.newprop = 99
          > def a(self):
          > x = A.a(self) # x is an A
          > x.__class__ = B
          > return x # I want x to be a B, i.e have b() and .newprop.
          > def b(self):
          > ...something...
          >
          > Yes, I know this is bogus. But I am not sure what
          > I should be doing.[/color]
          Typically, you might want to do something like:

          class B(A):
          ...
          def a(self):
          x = self.__class__. __new__(self.__ class__,...)
          # __new__ Usually gets no more args here, but

          x.__init__(...)
          # And here is where we do the actual init

          ...

          Hope this helps

          -Scott David Daniels
          Scott.Daniels@A cm.Org

          Comment

          • Paul McGuire

            #6
            Re: overriding method that returns base class object

            "Aahz" <aahz@pythoncra ft.com> wrote in message
            news:c0rmod$gso $1@panix3.panix .com...
            <snip>[color=blue]
            >
            > class A:
            > def a(self):
            > return self.__class__( )
            > --[/color]
            OP can't do this, can't get at source code of A.

            Assuming that you don't want to write __init__() to take an A argument, you
            need something like:

            class B(A):
            def makeFromAnA(oth er): # other is an A instance
            # construct a B - could pass initialization args from
            # other if this is part of the interface
            newB = B()

            # ... copy base class A fields from other to newB here ...

            # ... add B-ish stuff to newB here ...

            return newB
            makeFromAnA=sta ticmethod(makeF romAnA)

            def a(self):
            return B.makeFromAnA( A.a() )

            Here's an example:
            import random
            class Point2D(object) : # pretend this is implemented in C, so we can't
            change the code
            def __init__(self,x val,yval):
            self.x = xval
            self.y = yval
            def randomPoint():
            return Point2D( random.random() *100, random.random() *100 )
            randomPoint=sta ticmethod(rando mPoint)

            class Point3D(Point2D ): # not really good O-O design, but that's not the,
            um, point
            def __init__(self,x val,yval,zval):
            self.x = xval
            self.y = yval
            self.z = zval
            def make3DPtFrom2DP t(other):
            print "Make 3D pt from",other
            return Point3D(other.x ,other.y,0)
            # or if the __init__'s are not similar,
            # manually assign fields
            newPt3D = Point3D(0,0,0)
            newPt3D.x = other.x
            newPt3D.y = other.y
            return newPt3D
            make3DPtFrom2DP t=staticmethod( make3DPtFrom2DP t)
            def randomPoint():
            newPt = Point3D.make3DP tFrom2DPt( Point2D.randomP oint() )
            newPt.z = random.random() *100
            return newPt
            randomPoint=sta ticmethod(rando mPoint)

            print Point2D.randomP oint()
            print Point3D.randomP oint()

            -- Paul


            Comment

            • John Roth

              #7
              Re: overriding method that returns base class object


              "Stuart McGraw" <smcg4191@frii. RemoveThisToRep ly.com> wrote in message
              news:40315037$0 $199$75868355@n ews.frii.net...[color=blue]
              > Sorry, you are right, I wasn't clear. I mean B inherits from
              > A. Here is what I am trying to do...
              >
              > Class A has a method A.a() that returns an A. I want a
              > identical class but with an additional property .newprop
              > and method .b() And I want .a() to return a B, not an A.
              >
              > class B (A):
              > def __init__(self, *args, **kwds):
              > A.__init__(self , *args, **kwds)
              > self.newprop = 99
              > def a(self):
              > x = A.a(self) # x is an A
              > x.__class__ = B
              > return x # I want x to be a B, i.e have b() and .newprop.
              > def b(self):
              > ...something...
              >
              > Yes, I know this is bogus. But I am not sure what
              > I should be doing. And to correct what I originally
              > posted, A is implented in python (but I still can't
              > change it for administrative reasons), but it's properties
              > are declared with "__slots__ = [...]" if that makes a
              > difference. This is all in Python 2.3.3.[/color]

              What's bogus about it? You can change the
              class of an instance to be anything you want.
              The only issue might be the slots; I'm not all
              that familiar with what restrictions they might
              impose.

              Granted, there are relatively few cases
              where changing the class of an instance on
              the fly is actually better than the alternatives,
              but this might be one of them.

              John Roth
              [color=blue]
              >
              >
              > "Peter Hansen" <peter@engcorp. com> wrote in message[/color]
              news:4031481B.9 0B31C73@engcorp .com...[color=blue][color=green]
              > > Stuart McGraw wrote:[color=darkred]
              > > >
              > > > I have a class A from a third party that I cannot change
              > > > and is implemented in C. I derive my own class B from A
              > > > and add a couple new methods and override a method. The
              > > > problem is that A has a method (call it A.f() ) that creates
              > > > and returns a new A object. I need B.f() to return a B
              > > > object derived from A.f(). What is the best way to make
              > > > that happen?[/color]
              > >
              > > If I understand this correctly, it has nothing to do with the
              > > fact that the parent class is implemented in C and you just
              > > need to know a little uncommon syntax:
              > >
              > > class A:
              > > def f(self):
              > > return A()
              > > se
              > > class B(A):
              > > def f(self):
              > > obj = A.f(self)
              > > # do whatever you want to obj here
              > > return obj
              > >
              > > The key is what you mean by "a B object derived from A.f()". If
              > > by derived you mean something to do with _inheritance_, then
              > > either you don't understand inheritance or you weren't clear what
              > > you wanted.
              > >
              > > If you just mean you want B's f() to do something special to the
              > > A object that A.f() returns, then the above code should let you
              > > do that properly...
              > >
              > > -Peter[/color][/color]


              Comment

              • Paul Rubin

                #8
                Re: overriding method that returns base class object

                "Stuart McGraw" <smcg4191@frii. RemoveThisToRep ly.com> writes:[color=blue]
                > Class A has a method A.a() that returns an A. I want a
                > identical class but with an additional property .newprop
                > and method .b() And I want .a() to return a B, not an A.
                >
                > class B (A):
                > def __init__(self, *args, **kwds):
                > A.__init__(self , *args, **kwds)
                > self.newprop = 99
                > def a(self):
                > x = A.a(self) # x is an A
                > x.__class__ = B
                > return x # I want x to be a B, i.e have b() and .newprop.[/color]

                Ugh!!
                [color=blue]
                > Yes, I know this is bogus. But I am not sure what I should be doing.[/color]

                I think you have to make B into a container for an A. Something like:

                class B(A):
                def __init__(self, *args, **kwds):
                self.newprop = 99
                self.wrapped_A = A(*args, **kwds)
                def a(self):
                x = B()
                x.wrapped_A = A.a(self.wrappe d_A)
                return # I want x to be a B, i.e have b() and .newprop.
                def __getattr__(sel f, attr):
                # delegate all inherited operations to the wrapped A object
                return A.__getattr__(s elf.wrapped_A, attr)

                You might also be able to do something crazy, like change A's metaclass
                so that its __new__ operation can make a B under certain circumstances.

                Comment

                • Stuart McGraw

                  #9
                  Re: overriding method that returns base class object


                  "Scott David Daniels" <Scott.Daniels@ Acm.Org> wrote in message news:40316850$1 @nntp0.pdx.net. ..[color=blue]
                  > Stuart McGraw wrote:
                  >[color=green]
                  > > Sorry, you are right, I wasn't clear. I mean B inherits from
                  > > A. Here is what I am trying to do...
                  > >
                  > > Class A has a method A.a() that returns an A. I want a
                  > > identical class but with an additional property .newprop
                  > > and method .b() And I want .a() to return a B, not an A.
                  > >
                  > > class B (A):
                  > > def __init__(self, *args, **kwds):
                  > > A.__init__(self , *args, **kwds)
                  > > self.newprop = 99
                  > > def a(self):
                  > > x = A.a(self) # x is an A
                  > > x.__class__ = B
                  > > return x # I want x to be a B, i.e have b() and .newprop.
                  > > def b(self):
                  > > ...something...
                  > >
                  > > Yes, I know this is bogus. But I am not sure what
                  > > I should be doing.[/color]
                  > Typically, you might want to do something like:
                  >
                  > class B(A):
                  > ...
                  > def a(self):
                  > x = self.__class__. __new__(self.__ class__,...)
                  > # __new__ Usually gets no more args here, but
                  >
                  > x.__init__(...)
                  > # And here is where we do the actual init[/color]

                  I don't think this will work. A.a() returns an A, but one that
                  is initialized differently than an A() instance. That is, A.a()
                  does more that just __new__() and __init__() to it. So if I
                  do the above, I end up with a subtype (right word?) of an
                  A(), not an A.a().

                  Now I think that my B.a() must call A.a() and somehow
                  dynamically change the type of the object received? As suggesed
                  above, I tried to change the class (x.__class__ = B) but that
                  just results in an exception
                  TypeError: __class__ assignment: 'B' object layout differs from 'A'

                  Or maybe what I am trying to do is not possible in Python?

                  Comment

                  • Stuart McGraw

                    #10
                    Re: overriding method that returns base class object

                    "Paul Rubin" <http://phr.cx@NOSPAM.i nvalid> rote in message news:7xwu6mmm3v .fsf@ruckus.bro uhaha.com...[color=blue]
                    > "Stuart McGraw" <smcg4191@frii. RemoveThisToRep ly.com> writes:[color=green]
                    > > Class A has a method A.a() that returns an A. I want a
                    > > identical class but with an additional property .newprop
                    > > and method .b() And I want .a() to return a B, not an A.
                    > >
                    > > class B (A):
                    > > def __init__(self, *args, **kwds):
                    > > A.__init__(self , *args, **kwds)
                    > > self.newprop = 99
                    > > def a(self):
                    > > x = A.a(self) # x is an A
                    > > x.__class__ = B
                    > > return x # I want x to be a B, i.e have b() and .newprop.[/color]
                    >
                    > Ugh!!
                    >[color=green]
                    > > Yes, I know this is bogus. But I am not sure what I should be doing.[/color]
                    >
                    > I think you have to make B into a container for an A. Something like:
                    >
                    > class B(A):
                    > def __init__(self, *args, **kwds):
                    > self.newprop = 99
                    > self.wrapped_A = A(*args, **kwds)
                    > def a(self):
                    > x = B()
                    > x.wrapped_A = A.a(self.wrappe d_A)
                    > return # I want x to be a B, i.e have b() and .newprop.
                    > def __getattr__(sel f, attr):
                    > # delegate all inherited operations to the wrapped A object
                    > return A.__getattr__(s elf.wrapped_A, attr)
                    >
                    > You might also be able to do something crazy, like change A's metaclass
                    > so that its __new__ operation can make a B under certain circumstances.[/color]

                    Ahhhh.... I did not know about delegation. I do now, thanks.
                    A minor disadvantage is that, because I also delegate __setattr__
                    all the instance variable have to be assigned in the form
                    self.__dict__['var'], rather than self.var (as I discovered the hard
                    way). Ugly, but I can live with it. Thanks again.

                    Comment

                    • Scott David Daniels

                      #11
                      Re: overriding method that returns base class object

                      Stuart McGraw wrote:[color=blue]
                      > "Paul Rubin" <http://phr.cx@NOSPAM.i nvalid> rote in message news:7xwu6mmm3v .fsf@ruckus.bro uhaha.com...[color=green]
                      >>...
                      >>class B(A):
                      >> def __init__(self, *args, **kwds):
                      >> self.newprop = 99
                      >> self.wrapped_A = A(*args, **kwds)
                      >> def a(self):
                      >> x = B()
                      >> x.wrapped_A = A.a(self.wrappe d_A)
                      >> return # I want x to be a B, i.e have b() and .newprop.
                      >> def __getattr__(sel f, attr):
                      >> # delegate all inherited operations to the wrapped A object
                      >> return A.__getattr__(s elf.wrapped_A, attr)
                      >>
                      >>You might also be able to do something crazy, like change A's metaclass
                      >>so that its __new__ operation can make a B under certain circumstances.[/color]
                      >
                      > Ahhhh.... I did not know about delegation. I do now, thanks.
                      > A minor disadvantage is that, because I also delegate __setattr__
                      > all the instance variable have to be assigned in the form
                      > self.__dict__['var'], rather than self.var (as I discovered the hard
                      > way). Ugly, but I can live with it. Thanks again.[/color]

                      If you can separate the names, you can do something like:

                      class B(object):
                      def __init__(self, *args, **kwargs):
                      self._a = A(*args, **kwargs)
                      self.newprop = 99
                      def __setattr__(sel f, name, val):
                      if name.startswith ('_') or name == 'newprop':
                      self.__dict__[name] = val
                      else:
                      setattr(self._a , name, val)
                      def getattr(self, name):
                      return getattr(self._a , name)

                      --
                      -Scott David Daniels
                      Scott.Daniels@A cm.Org

                      Comment

                      Working...