overriding method that returns base class object

Discussion in 'Python' started by Stuart McGraw, Feb 16, 2004.

  1. 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?
    Stuart McGraw, Feb 16, 2004
    #1
    1. Advertising

  2. Stuart McGraw

    Peter Hansen Guest

    Stuart McGraw wrote:
    >
    > 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?


    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
    Peter Hansen, Feb 16, 2004
    #2
    1. Advertising

  3. 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" <> wrote in message news:...
    > Stuart McGraw wrote:
    > >
    > > 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?

    >
    > 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
    Stuart McGraw, Feb 16, 2004
    #3
  4. Stuart McGraw

    Aahz Guest

    In article <40315037$0$199$>,
    Stuart McGraw <> wrote:
    >
    >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.


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

    "Argue for your limitations, and sure enough they're yours." --Richard Bach
    Aahz, Feb 17, 2004
    #4
  5. Stuart McGraw wrote:

    > 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.

    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 David Daniels, Feb 17, 2004
    #5
  6. Stuart McGraw

    Paul McGuire Guest

    "Aahz" <> wrote in message
    news:c0rmod$gso$...
    <snip>
    >
    > class A:
    > def a(self):
    > return self.__class__()
    > --

    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(other): # 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=staticmethod(makeFromAnA)

    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,xval,yval):
    self.x = xval
    self.y = yval
    def randomPoint():
    return Point2D( random.random()*100, random.random()*100 )
    randomPoint=staticmethod(randomPoint)

    class Point3D(Point2D): # not really good O-O design, but that's not the,
    um, point
    def __init__(self,xval,yval,zval):
    self.x = xval
    self.y = yval
    self.z = zval
    def make3DPtFrom2DPt(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
    make3DPtFrom2DPt=staticmethod(make3DPtFrom2DPt)
    def randomPoint():
    newPt = Point3D.make3DPtFrom2DPt( Point2D.randomPoint() )
    newPt.z = random.random()*100
    return newPt
    randomPoint=staticmethod(randomPoint)

    print Point2D.randomPoint()
    print Point3D.randomPoint()

    -- Paul
    Paul McGuire, Feb 17, 2004
    #6
  7. Stuart McGraw

    John Roth Guest

    "Stuart McGraw" <> wrote in message
    news:40315037$0$199$...
    > 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.


    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

    >
    >
    > "Peter Hansen" <> wrote in message

    news:...
    > > Stuart McGraw wrote:
    > > >
    > > > 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?

    > >
    > > 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
    John Roth, Feb 17, 2004
    #7
  8. Stuart McGraw

    Paul Rubin Guest

    "Stuart McGraw" <> writes:
    > 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.


    Ugh!!

    > Yes, I know this is bogus. But I am not sure what I should be doing.


    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.wrapped_A)
    return # I want x to be a B, i.e have b() and .newprop.
    def __getattr__(self, attr):
    # delegate all inherited operations to the wrapped A object
    return A.__getattr__(self.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.
    Paul Rubin, Feb 17, 2004
    #8
  9. "Scott David Daniels" <> wrote in message news:40316850$...
    > Stuart McGraw wrote:
    >
    > > 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.

    > 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


    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?
    Stuart McGraw, Feb 17, 2004
    #9
  10. "Paul Rubin" <http://> rote in message news:...
    > "Stuart McGraw" <> writes:
    > > 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.

    >
    > Ugh!!
    >
    > > Yes, I know this is bogus. But I am not sure what I should be doing.

    >
    > 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.wrapped_A)
    > return # I want x to be a B, i.e have b() and .newprop.
    > def __getattr__(self, attr):
    > # delegate all inherited operations to the wrapped A object
    > return A.__getattr__(self.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.


    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.
    Stuart McGraw, Feb 17, 2004
    #10
  11. Stuart McGraw wrote:
    > "Paul Rubin" <http://> rote in message news:...
    >>...
    >>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.wrapped_A)
    >> return # I want x to be a B, i.e have b() and .newprop.
    >> def __getattr__(self, attr):
    >> # delegate all inherited operations to the wrapped A object
    >> return A.__getattr__(self.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.

    >
    > 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.


    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__(self, 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 David Daniels, Feb 17, 2004
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Teis Draiby
    Replies:
    3
    Views:
    449
    Pete Vidler
    Apr 2, 2004
  2. Guest
    Replies:
    2
    Views:
    428
  3. Tinku
    Replies:
    3
    Views:
    1,172
    Alf P. Steinbach
    Jan 31, 2010
  4. Karan Rajput
    Replies:
    2
    Views:
    140
    Abinoam Jr.
    Dec 22, 2010
  5. Koszalek Opalek

    Overriding a class method with an object method

    Koszalek Opalek, Jul 2, 2007, in forum: Perl Misc
    Replies:
    8
    Views:
    150
    -berlin.de
    Jul 6, 2007
Loading...

Share This Page