latil
latil

Reputation: 11

Replace method with method of instance of different class

I just tried to make a system with some classes with similar parent class, which dynamically assigns their method between them, It looks like one function "transform(from, to)", which doing smth like from.foo = to.foo

So, you see, that my problem is difficult with Python, so I'm asking for help

My first try was

def transform(a, b):
    a.foo = b.foo


class A:
    def foo(self):
        pass


class B(A):
    def foo(self):
        print("bar")
        transform(self, C())


class C(A):
    def foo(self):
        print("foo")
        transform(self, B())

b = C()
b.foo()
b.foo()
b.foo()
b.foo()

I want to get from it smth like

foo
bar
foo
bar

But I get

foo
bar
bar
bar

The funniest moment of all is that first conversion working, but next.


My next try was

class A:
    def foo(self):
        pass

    def transform(self, to):
        self.foo = to.foo


class B(A):
    def foo(self):
        print("bar")
        self.transform(C())


class C(A):
    def foo(self):
        print("foo")
        self.transform(B())

b = C()
b.foo()
b.foo()
b.foo()
b.foo()

and I got the same result. Do you have any idea how to manage this conversion?

Upvotes: 0

Views: 49

Answers (1)

Ruzihm
Ruzihm

Reputation: 20269

In your code, it first runs a.foo = b.foo, where a was the object created at b = C(), and b was the object created at B(). Then when a.foo() is next run, it runs B's foo(self) where self is that B() object. There, it runs transform(self, C()) where self is still the object created with B(), not the object at b. Basically, b is only modified once then never modified again.

Instead, you should get the unbound function object of foo with b.foo.__func__ before assigning it to the other one, or the self in foo will refer to the object B() instead of b. Then, you can bind it back to the destination object with types.MethodType:

from types import MethodType

def transform(a, b):
    a.foo = MethodType(b.foo.__func__, a)

class A:
    def foo(self):
        pass


class B(A):
    def foo(self):
        print("bar")
        transform(self, C())


class C(A):
    def foo(self):
        print("foo")
        transform(self, B())

b = C()
b.foo()
b.foo()
b.foo()
b.foo()
foo
bar
foo
bar

Your 2nd attempt is also fixed by doing the same thing:

from types import MethodType

class A:
    def foo(self):
        pass

    def transform(self, to):
        self.foo = MethodType(to.foo.__func__, self)


class B(A):
    def foo(self):
        print("bar")
        self.transform(C())


class C(A):
    def foo(self):
        print("foo")
        self.transform(B())

b = C()
b.foo()
b.foo()
b.foo()
b.foo()
foo
bar
foo
bar

Upvotes: 1

Related Questions