can a subclass method determine if called by superclass?

Discussion in 'Python' started by Peter, Jan 4, 2012.

  1. Peter

    Peter Guest

    Situation: I am subclassing a class which has methods that call other
    class methods (and without reading the code of the superclass I am
    discovering these by trial and error as I build the subclass - this is
    probably why I may have approached the problem from the wrong
    viewpoint :)).

    Problem: when overriding one of these "indirectly called" superclass
    methods I would like to take differing actions (in the subclass
    instance) depending on whether it is the superclass or the subclass
    instance performing the call.

    Question: Is there any way to determine in a method whether it is
    being called by the superclass or by a method of the subclass
    instance?

    Now I suspect that what I am doing is actually very muddy thinking :)
    and I don't want to attempt to explain why I am approaching the design
    this way as an explanation would require too much work - I will
    consider an alternative inheritance approach while waiting an answer,
    but the answer to the question interested me (even if I do a redesign
    and come up with a more "elegant" approach to the problem).

    Thanks
    Peter
     
    Peter, Jan 4, 2012
    #1
    1. Advertising

  2. Peter

    Ian Kelly Guest

    On Wed, Jan 4, 2012 at 3:42 PM, Peter <> wrote:
    > Situation: I am subclassing a class which has methods that call other
    > class methods (and without reading the code of the superclass I am
    > discovering these by trial and error as I build the subclass - this is
    > probably why I may have approached the problem from the wrong
    > viewpoint :)).
    >
    > Problem: when overriding one of these "indirectly called" superclass
    > methods I would like to take differing actions (in the subclass
    > instance) depending on whether it is the superclass or the subclass
    > instance performing the call.
    >
    > Question: Is there any way to determine in a method whether it is
    > being called by the superclass or by a method of the subclass
    > instance?


    Well, you could get the previous stack level using
    traceback.extract_stack() and check the filename. But it sounds like
    what you actually have are two different methods -- one that is used
    by the superclass, and one that only the subclass knows about and
    uses. Why not implement it as such?
     
    Ian Kelly, Jan 4, 2012
    #2
    1. Advertising

  3. Peter

    Peter Guest

    On Jan 5, 10:09 am, Ian Kelly <> wrote:

    >
    > Well, you could get the previous stack level using
    > traceback.extract_stack() and check the filename.  But it sounds like
    > what you actually have are two different methods -- one that is used
    > by the superclass, and one that only the subclass knows about and
    > uses.  Why not implement it as such?


    Thanks Ian - that is one possibility.

    I am trying to create a subclass with slightly different functionality
    and use it with an existing code base i.e. there is already one or
    more modules that instantiate the current superclass and I want to
    just drop in this new class to replace it with no ripples up the line
    (so to speak). The new class implements some interface changes that
    can safely be hidden from the rest of the application.
     
    Peter, Jan 4, 2012
    #3
  4. On Wed, 04 Jan 2012 15:37:55 -0800, Peter wrote:

    > I am trying to create a subclass with slightly different functionality
    > and use it with an existing code base i.e. there is already one or
    > more modules that instantiate the current superclass and I want to
    > just drop in this new class to replace it with no ripples up the line
    > (so to speak). The new class implements some interface changes that
    > can safely be hidden from the rest of the application.


    This is *exactly* the idea behind subclassing. I don't understand your
    problem, can you explain more?

    If you want to change behaviour of an object, you subclass it, then
    override or overload the methods you want to change. You certainly
    shouldn't be changing the superclass to recognise when it is being called
    from a subclass! That's completely the wrong approach -- you should put
    all the new behaviour in the new class.


    # WRONG! Don't do this.

    class Parent(object):
    def method(self, arg):
    if type(self) is not Parent:
    # Must be a subclass.
    print("Called from a subclass. But which one?")
    print("Doing method stuff.")

    class Child(Parent):
    pass


    # RIGHT! Do this instead.

    class Parent(object):
    def method(self, arg):
    print("Doing method stuff.")

    class Child(Parent):
    def method(self, arg):
    # Overload an existing method.
    print("Called from Child subclass.")
    super().method(arg) # Python 3 only
    # Python 2 use: super(Child, self).method(arg)


    If method() returns a result, you can capture the result of calling the
    superclass method and then modify it as needed. Or you can override the
    method completely, and not call the parent method() at all.

    Now you can use Child() anywhere that you can use Parent and the caller
    shouldn't even notice. Or at least that is the idea behind subclassing,
    although it is possible to break it. You will be okay if the caller uses
    duck-typing, or isinstance checks, but not if they do exact type checks
    (which is almost always the wrong thing to do).

    c = Child()

    # Duck-typing works:
    hasattr(c, 'method') # returns True

    # So do isinstance checks:
    isinstance(c, Parent) # returns True

    # but this doesn't and defeats the purpose of having subclasses:
    type(c) is Parent # returns False, you shouldn't do this!


    If the caller does do exact type checks, then almost certainly it should
    be considered a bug in their code and they should be beaten with a clue-
    bat and told to use isinstance (good) or duck-typing (better still).


    If I have misunderstood your problem, can you give a concrete (but
    simple) example of what you are trying to do?



    --
    Steven
     
    Steven D'Aprano, Jan 5, 2012
    #4
  5. Peter wrote:
    > Situation: I am subclassing a class which has methods that call other
    > class methods (and without reading the code of the superclass I am
    > discovering these by trial and error as I build the subclass - this is
    > probably why I may have approached the problem from the wrong
    > viewpoint :)).
    >
    > Problem: when overriding one of these "indirectly called" superclass
    > methods I would like to take differing actions (in the subclass
    > instance) depending on whether it is the superclass or the subclass
    > instance performing the call.
    >
    > Question: Is there any way to determine in a method whether it is
    > being called by the superclass or by a method of the subclass
    > instance?
    >
    > Now I suspect that what I am doing is actually very muddy thinking :)
    > and I don't want to attempt to explain why I am approaching the design
    > this way as an explanation would require too much work - I will
    > consider an alternative inheritance approach while waiting an answer,
    > but the answer to the question interested me (even if I do a redesign
    > and come up with a more "elegant" approach to the problem).
    >
    > Thanks
    > Peter
    >

    As you suspected, this is probably the wrong approach.

    However since you asked for a solution anyway :eek:)

    class Parent(object):
    def foo(self):
    # implementation by subclasses is still REQUIRED
    if self.__class__ is Parent:
    raise NotImplementedError()
    # common code for all foo methods
    print "calling foo"

    class Child(Parent):
    def foo(self):
    # You can still call the virtual method which contains some code
    Parent.foo(self)
    # here the custom code


    p = Parent()
    c = Child()


    c.foo()
    p.foo()

    Note that this is not the best approach, still acceptable because there
    is no code specific to a subclass in the base class.

    JM
     
    Jean-Michel Pichavant, Jan 5, 2012
    #5
  6. Jean-Michel Pichavant wrote:
    > Peter wrote:
    >> Situation: I am subclassing a class which has methods that call other
    >> class methods (and without reading the code of the superclass I am
    >> discovering these by trial and error as I build the subclass - this is
    >> probably why I may have approached the problem from the wrong
    >> viewpoint :)).
    >>
    >> Problem: when overriding one of these "indirectly called" superclass
    >> methods I would like to take differing actions (in the subclass
    >> instance) depending on whether it is the superclass or the subclass
    >> instance performing the call.
    >>
    >> Question: Is there any way to determine in a method whether it is
    >> being called by the superclass or by a method of the subclass
    >> instance?
    >>
    >> Now I suspect that what I am doing is actually very muddy thinking :)
    >> and I don't want to attempt to explain why I am approaching the design
    >> this way as an explanation would require too much work - I will
    >> consider an alternative inheritance approach while waiting an answer,
    >> but the answer to the question interested me (even if I do a redesign
    >> and come up with a more "elegant" approach to the problem).
    >>
    >> Thanks
    >> Peter
    >>

    > As you suspected, this is probably the wrong approach.
    >
    > However since you asked for a solution anyway :eek:)
    >
    > class Parent(object):
    > def foo(self):
    > # implementation by subclasses is still REQUIRED
    > if self.__class__ is Parent:
    > raise NotImplementedError()
    > # common code for all foo methods
    > print "calling foo"
    >
    > class Child(Parent):
    > def foo(self):
    > # You can still call the virtual method which contains some code
    > Parent.foo(self)
    > # here the custom code
    >
    >
    > p = Parent()
    > c = Child()
    >
    >
    > c.foo()
    > p.foo()
    >
    > Note that this is not the best approach, still acceptable because
    > there is no code specific to a subclass in the base class.
    >
    > JM

    I just realized I didn't addressed the problem you described, sorry,
    just ignore my mail.

    JM
     
    Jean-Michel Pichavant, Jan 5, 2012
    #6
  7. Peter

    Peter Guest

    Thanks for the help guys - it appears there is no better way than Ian
    suggested.

    I have restructured my class hierarchy so the problem has now "gone
    away".

    It would have been nice to discover some previously unknown (to me at
    least!) Python trick, but such is life :)

    Regards
    Peter
     
    Peter, Jan 5, 2012
    #7
    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. jstorta
    Replies:
    3
    Views:
    457
    jstorta
    Feb 20, 2006
  2. Evan Klitzke
    Replies:
    0
    Views:
    374
    Evan Klitzke
    Aug 2, 2007
  3. bart van deenen
    Replies:
    6
    Views:
    786
    bart van deenen
    Mar 3, 2009
  4. Rob Boellaard
    Replies:
    7
    Views:
    116
    Rob Boellaard
    Jun 14, 2008
  5. Marcos
    Replies:
    9
    Views:
    145
    Marcos
    Aug 17, 2009
Loading...

Share This Page