python:为第三方类编写包装器

3 投票
3 回答
2058 浏览
提问于 2025-04-16 10:13

我需要一个第三方模块m里面的类X的一些功能。我可以直接使用m.X,但将来我可能需要把m.X换成另一个类n.Y(比如,如果我发现了更好的实现方式)。

我希望在这种情况下,其他代码不需要做任何修改。

现在,我想要m.X的完整接口,包括初始化,保持不变。所以我为m.X写了一个包装器W,代码如下:

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的包装器会有问题吗?

3 个回答

0

这要看你用的 m.X 和 n.Y 这两个方法有多大的不同,不过其实可以简单到像这样:

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

class W(foo):
    pass

这样你的代码就会自动反映出新的模块,可能会减少你在整个代码中需要做的修改。

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可能不会正常工作,但在第一个例子中是可以正常工作的。)

在某些情况下,使用赋值可能会和一些开发工具不太兼容。在这种情况下:

class W(m.X): pass

也会产生相同的结果,不过会多一些开销,因为W的实例实际上只是m.X的实例,因为W是一个子类:使用W=m.X; W(args)会创建一个m.X的实例。

撰写回答