Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overwriting class methods without inheritance (python)

Tags:

python

First, if you guys think the way I'm trying to do things is not Pythonic, feel free to offer alternative suggestions.

I have an object whose functionality needs to change based on outside events. What I've been doing originally is create a new object that inherits from original (let's call it OrigObject()) and overwrites the methods that change (let's call the new object NewObject()). Then I modified both constructors such that they can take in a complete object of the other type to fill in its own values based on the passed in object. Then when I'd need to change functionality, I'd just execute myObject = NewObject(myObject).

I'm starting to see several problems with that approach now. First of all, other places that reference the object need to be updated to reference the new type as well (the above statement, for example, would only update the local myObject variable). But that's not hard to update, only annoying part is remembering to update it in other places each time I change the object in order to prevent weird program behavior.

Second, I'm noticing scenarios where I need a single method from NewObject(), but the other methods from OrigObject(), and I need to be able to switch the functionality on the fly. It doesn't seem like the best solution anymore to be using inheritance, where I'd need to make M*N different classes (where M is the number of methods the class has that can change, and N is the number of variations for each method) that inherit from OrigObject().

I was thinking of using attribute remapping instead, but I seem to be running into issues with it. For example, say I have something like this:

def hybrid_type2(someobj, a):
    #do something else
    ...

class OrigObject(object):
    ...
    def hybrid_fun(self, a):
        #do something
        ...

    def switch(type):
        if type == 1:
            self.hybrid_fun = OrigObject.hybrid_fun
        else:
            self.fybrid_fun = hybrid_type2

Problem is, after doing this and trying to call the new hybrid_fun after switching it, I get an error saying that hybrid_type2() takes exactly 2 arguments, but I'm passing it one. The object doesn't seem to be passing itself as an argument to the new function anymore like it does with its own methods, anything I can do to remedy that?

I tried including hybrid_type2 inside the class as well and then using self.hybrid_fun = self.hybrid_type2 works, but using self.hybrid_fun = OrigObject.hybrid_fun causes a similar error (complaining that the first argument should be of type OrigObject). I know I can instead define OrigObject.hybrid_fun() logic inside OrigObject.hybrid_type1() so I can revert it back the same way I'm setting it (relative to the instance, rather than relative to the class to avoid having object not be the first argument). But I wanted to ask here if there is a cleaner approach I'm not seeing here? Thanks

EDIT: Thanks guys, I've given points for several of the solutions that worked well. I essentially ended up using a Strategy pattern using types.MethodType(), I've accepted the answer that explained how to do the Strategy pattern in python (the Wikipedia article was more general, and the use of interfaces is not needed in Python).

like image 615
Alexander Tsepkov Avatar asked Dec 17 '22 12:12

Alexander Tsepkov


1 Answers

You want the Strategy Pattern.

like image 141
Ignacio Vazquez-Abrams Avatar answered Jan 14 '23 14:01

Ignacio Vazquez-Abrams