max
max

Reputation: 52273

python: writing a wrapper around a third-party class

I need some functionality from a class X of a third-party module m. I could just use m.X directly, but I may need to replace m.X with another class n.Y in the future (e.g., if I discover a better implementation).

I'd like to avoid changing the rest of the code in such a situation.

For now, I want the full interface of m.X, including initialization, to pass through unchanged. I wrote a wrapper W for m.X as follows:

class W(m.X):
    def __init__(self, *args):
        super().__init__(*args)

In the future, should the need arise, I plan to rewrite the above as:

class W(n.Y):
    def __init__(self, *args):
        super().__init__(*args)
    # override instance methods of n.Y that don't share the semantics with m.X
    # for example, in case f1 is hard to replicate in n.Y:
    # def f1(self, *args):
    #     print("this method is no longer available")
    #     raise MyDeprecatedMethod()
    # for example, in case f2 needs to be recalculated
    # def f2(self, *args):
          # do the calculations required to keep W.f2 unchanged 

Is my current wrapper for m.X acceptable? Are there are problems with it, or with the planned wrapper for n.Y?

Upvotes: 3

Views: 2240

Answers (3)

BoltzmannBrain
BoltzmannBrain

Reputation: 5392

This would depend on how different m.X and n.Y are in their methods you're using, but it could be as simple as

try:
    import n.Y as foo
except ImportError:
    import m.X as foo

class W(foo):
    pass

so your code reflects the new module automatically, potentially minimizing the changes you need to make throughout your codebase.

Upvotes: 0

Zooba
Zooba

Reputation: 11438

The simplest method is to write:

W = m.X

Practically everything in Python is a first-class object - including types. A class is almost indistinguishable from any other variable, for example:

def W(*args, **kwargs):
    return m.X(*args, **kwargs)

can instantiate an instance of m.X while appearing that W is the actual name of it. (Note that with this method isinstance will not work correctly - it will work fine with the first example.)

In some cases, using assignment may not play nicely with IDEs. In this case:

class W(m.X): pass

will also produce the same result, though with the added overhead in that instances of W are only instances of m.X because W is a subclass: using W=m.X; W(args) will create an instance of m.X.

Upvotes: 2

erbridge
erbridge

Reputation: 1386

You could simply use

class W(m.X):
    pass

which inherits m.X.__init__() by default.

Upvotes: 3

Related Questions