用Python封装的C++类的SIP补丁

4 投票
1 回答
928 浏览
提问于 2025-04-18 05:21

我正在为一个用C++写的库创建一个Python的封装,这个库实现了一些底层的机器对机器(M2M)通信。我使用的是Riverbank的SIP封装生成器。

这个C++类里面有一个方法:

class Bar {
public:
    enum Status {
        ...
    };
    void setStatus(Status s);
    Status getStatus() const;
    ...
};

这个类在模块foo里面。

SIP使用了它自己的一种枚举类型,但出于一些原因,我想用Python 3.4标准库里的枚举。

我觉得通过Python的C API访问Python定义的类几乎不可能,所以我决定在__init__.py里对封装的类进行修改。这样做的主要原因是我想在C/C++/SIP中处理一些底层的工作,然后在Python中对这个类进行优化(比如添加参数验证,并给出合理的错误信息)。

Python的__init__.py部分大概是这样的:

from foo import Bar

class Status(IntEnum):
    ONE = 1
    TWO = 2
    ... and so on ...
Status.__module__ = 'Bar.Status'
Bar.Status = Status
Bar.status = property(...)

Bar.status将会接受并返回一个好用的、符合Python风格的Bar.Status枚举。

我期望的结果是这样的:

class Bar(object):
    class Status(IntEnum):
         ...
    ...

我在想,这种方法是否有什么问题,特别是在导入时对对象进行修改。

1 个回答

1

我用另一种方法解决了这个问题,感觉还不错。

我们来看看一个C++库,它里面有两个类:

  1. Foo
  2. FooFactory

这个包装库包含了一个叫做 libfoo 的包(是用Python的C API创建的),还有一个更符合Python风格的包 foo(是用普通的Python创建的)。我们并不直接使用 libfoo 包,而是导入 foo

foo__init__.py 文件内容如下:

from libfoo import Foo, FooFactory

# both are naked wrappers with ugly API derived from C++
# I defined some pythonic sugar that makes them nice to use

class FooPythonicGoodies(object):
    # add pythonic goodies here
    def quack(self):
        pass

# Merge them
Foo.__bases__ = Foo.__bases__ + (FooPythonicGoodies,)

现在,当我在代码的任何地方这样做的时候:

from foo import Foo, FooFactory

a = Foo()
a.quack()

# Factory is a C++ wrapped class that returns wrapped foo
# objects WITH FooPythonicGoodies!
factory = FooFactory()
b = factory.create_foo()
b.quack() # that works too!

这样我就可以用更符合Python风格的API来美化那些不太符合Python风格的C++类。

撰写回答