views:

271

answers:

3

Can I force a parent class to call a derived class's version of a function?

class Base(object):
    attr1 = ''
    attr2 = ''

    def virtual(self):
        pass               # doesn't do anything in the parent class

    def func(self):
        print "%s, %s" % (self.attr1, self.attr2)
        self.virtual()

and a class that derives from it

class Derived(Base):
    attr1 = 'I am in class Derived'
    attr2 = 'blah blah'

    def virtual(self):
        # do stuff...
        # do stuff...

Clearing up vagueness:

d = Derived()
d.func()         # calls self.virtual() which is Base::virtual(), 
                 #  and I need it to be Derived::virtual()
+3  A: 

If you instantiate a Derived (say d = Derived()), the .virtual that's called by d.func() is Derived.virtual. If there is no instance of Derived involved, then there's no suitable self for Derived.virtual and so of course it's impossible to call it.

Alex Martelli
your right of course... been too quick again. It happens to me too often these days ;-(
jldupont
I changed the question to better explain what i mean
W_P
Paul, what you say just can't happen (with the code you show). Running the code you show, with `print "this is Derived.virtual!"` as the body of `Derived.virtual`, does of course print exactly this string (after the `I am in class Derived, blah blah` string of course). Your bug must be in some other part of code that you're not showing.
Alex Martelli
A: 

Ok, I just ended up passing the instance of virtual() I needed to func()

class Base(object):
    attr1 = ''
    attr2 = ''

    def __init__(self):
        pass

    def virtual(self):
        pass

    def func(self, cb):
         print "%s, %s" % (self.attr1, self.attr2)
         cb()

class Derived(Base):
    attr1 = 'I am in class Derived'
    attr2 = 'blah blah'

    def virtual(self):
        # do stuff...
        # do stuff...


d = Derived()
d.func(d.virtual)
W_P
But see comments your original code works
Mark
it never did work for me the way it did for you
W_P
A: 

It isn't impossible -- there is a way around this actually, and you don't have to pass in the function or anything like that. I am working on a project myself where this exact problem came up. Here is the solution:


class Base(): # no need to explicitly derive object for it to work
    attr1 = 'I am in class Base'
    attr2 = 'halb halb'

    def virtual(self):
        print "Base's Method"

    def func(self):
        print "%s, %s" % (self.attr1, self.attr2)
        self.virtual()

class Derived(Base):
    attr1 = 'I am in class Derived'
    attr2 = 'blah blah'

    def __init__(self):
  # only way I've found so far is to edit the dict like this
        Base.__dict__['_Base_virtual'] = self.virtual

    def virtual(self):
        print "Derived's Method"

if __name__ == '__main__':
    d = Derived()
    d.func()

Jyaan