Search code examples
pythonclassmethodsattributes

Override a method by an attribute at instance level


This is related to this question however the methods described there do not work.

I have a certain class Dog with a method woofwoof and an attribute woof. There is a second method bark which returns woofwoof(). For a given instance of Dog, I want to redefine bark so that it returns the value of woof. Importantly, bark must remain a method given downstream code relies on calling bark.

See a minimum working example below.

class Dog:
    woof = 'woof'
    def woofwoof(self):
        return 'woof woof'
    def woOof(self):
        return 'woOof'
    def bark(self):
        return self.woofwoof()

def test(foo):
    print(type(foo.bark))
    print(foo.bark())

foo = Dog()
test(foo)

foo.bark = foo.woOof
test(foo)

foo.bark = foo.woof
test(foo)

The above code yields:

<class 'method'>
woof woof

<class 'method'>
woOof

<class 'str'>
TypeError: 'str' object is not callable

However the output I want from the last 2 lines is:

<class 'method'>
woof

That is preserve the type of bark as a method, but make it return the value of attribute woof (in particular so that if I change the value of woof later on, bark returns the updated value when called).


Solution

  • The value of foo.bark has to be a callable, e.g. a function or method. You can't call a string. And even if you could, the assignment would set it to the current string, it wouldn't track changes to the attribute.

    Define a method that returns self.woof, and assign that to foo.bark.

    class Dog:
        woof = 'woof'
        def woofwoof(self):
            return 'woof woof'
        def woOof(self):
            return 'woOof'
        def bark(self):
            return self.woofwoof()
        def returnWoof(self):
            return self.woof
    
    foo = Dog()
    foo.bark = foo.returnWoof
    test(foo)