0

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

Daneel Olivaw
  • 2,077
  • 4
  • 15
  • 23

2 Answers2

1

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)
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

For the given instance, just redefine the method. At a high level, this is basically the same answer given here: https://stackoverflow.com/a/76930897/218663 by @barmar which I upvoted.

The only difference here is that I'm not going to add in a utility method to the class Dog(), but monkey patch the instance via functools.partial. You might view this as a strength or a weakness of my solution.

import functools

class Dog:
    woof = 'woof'

    def woofwoof(self):
        return 'woof woof'

    def bark(self):
        return self.woofwoof()

foo = Dog()
bar = Dog()

## ----------------
## for a given instace, return self.woof
## ----------------
foo.bark = functools.partial(lambda self: self.woof, foo)
## ----------------

print(foo.bark())
print(bar.bark())
JonSG
  • 10,542
  • 2
  • 25
  • 36