Python:编写第三方类的包装器

3

我需要从第三方模块m的类X中获取一些功能。我可以直接使用m.X,但是将来可能需要用另一个类n.Y替换m.X(例如,如果我发现更好的实现)。

在这种情况下,我希望避免改变其余代码。目前,我想要通过以下方式编写一个包装器W,以便完全保留m.X的接口,包括初始化:

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

在未来,如果需要的话,我计划将上述内容重写为:
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 

我的m.X包装器目前可用吗?它有问题吗,或者计划中的n.Y包装器有问题吗?


看起来不错(至少,这是我做的方式) - Kyle Wild
你真正需要多少包装?如果唯一的问题是保护代码中其他部分不受名称更改的影响,那么简单地使用“W = m.X”就足够了,对吧? - Karl Knechtel
3个回答

3
您可以简单地使用。
class W(m.X):
    pass

默认情况下,它会继承 m.X.__init__()

2
最简单的方法是写下以下内容:


W = m.X

几乎所有Python中的对象都是一等公民,包括类型。例如,类几乎与任何其他变量无法区分:
def W(*args, **kwargs):
    return m.X(*args, **kwargs)

可以实例化一个m.X的实例,同时看起来W是它的实际名称。(请注意,使用这种方法isinstance将不能正确工作 - 它将与第一个示例一样正常工作。)

在某些情况下,使用赋值可能无法与IDE很好地配合使用。在这种情况下:

class W(m.X): pass

使用W=m.X; W(args)将创建m.X的实例,尽管有额外的开销,因为W的实例仅是m.X的实例,因为W是一个子类。


1
如果OP想要覆盖已更改的函数,他们可以执行def myFun(self,*args): doSomething()W.f1=myFun; W.f2=myFun等。 - erbridge
2
@Fantasizer 这样做可以起作用,但也会应用于 m.X。最好通过创建一个新类并仅覆盖所需的方法来执行重写函数(除非它正在更改,否则无需执行 __init__)。 - Zooba

0
这取决于您使用的方法中m.X和n.Y有多不同,但它可能很简单。
try:
    import n.Y as foo
except ImportError:
    import m.X as foo

class W(foo):
    pass

因此,您的代码会自动反映新模块,从而可能最小化您需要在整个代码库中进行的更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接