【问题标题】:Wrapping C for object oriented programming in Python在 Python 中为面向对象编程包装 C
【发布时间】:2021-02-10 05:59:29
【问题描述】:

我编写了一个C 代码用于与 Raspberry Pi 进行芯片通信,其中包括几个公共功能。

为了将其包装在Python 中使用,我将代码编译成so 文件并使用ctypes,因为对我来说这是最简单的方法。

但是,这种方法有两个缺陷:

  1. Python 代码有时比较古怪。例如,如果函数接受一个数组作为参数,那么 Python 中的编码如下所示:
MCP4728 = cdll.LoadLibrary("./MCP4728.so")

multipleexternal = MCP4728.multipleexternal
multipleexternal.restype = c_int
multipleexternal.argtypes = [POINTER(c_float), c_bool]

voltages=[0.5,1.5,2.5,2.5]
floats = (c_float*4)(*voltages)
multipleinternal(floats,False)
  1. 我不知道如何将其转换为面向对象编程,所以一个可以同时连接两个不同的芯片

  2. 最后,我想将我的软件公开并发布到github。在这种情况下,可能会首选其他一些包装方法。

我知道还有许多其他方法可以为Python 包装C 代码,如here 所述。您能给我建议使用哪种方法,甚至是最合适的面向对象编程示例吗?

感谢您的帮助!

编辑:

这不仅仅是语法的问题,也是概念的问题。 C 库中的函数可用于所有芯片,但每个芯片都需要在库中保存一组不同的变量。

那我该怎么办?在 Python 中定义类,其中创建新对象意味着在连接到该对象的库中创建新的struct?或者也许为每个对象使用C 库的新实例?或者也许在C 库中创建类/对象?我完全一无所知。

【问题讨论】:

  • 让我们专注于您的同时使用两个不同的芯片问题。是什么特别阻止你这样做?请注意,C 支持 struct 对象,因此除非您需要继承之类的东西(这不太可能)...
  • @robertharvey 哦,我不知道。我认为C没有OOP支持。也许我应该查一下,因为我从来没有在 C 上做过 OOP。
  • 有一些方法可以在 C 中支持成熟的 OOP,但我猜你不会需要它。
  • C 中的 OOP 非常简单,但在编码时必须保持纪律。基本上,您为每个函数调用提供对其数据类型存储对象的引用。当您声明使用“self”的函数时,您也可以从 Python 中了解到这种编码模式。 OOP 是一种编码模式,而不是一种特性。
  • 重点是,您认为您需要 OOP,但您可能不需要。您可能需要为每个芯片维护单独的状态。

标签: python c oop


【解决方案1】:

大概您说的是 Microchip MCP4728。这是一个 I2C 连接设备,因此它在 I2C 总线上有一个地址。如果您在默认出厂条件下使用它,地址为 0b1100000。因此,要拥有“两个不同的芯片”,您需要 2 个独立的 I2C 总线,或者利用 MCP4728 上的可重新编程寻址并将其中一个设置为 0b1100001(为此您需要控制 /LDAC 引脚在设备上),以便 2 个可以存在于一条 I2C 总线上。

无论哪种方式,您都需要某种设备“上下文”,您可以将其传递给您的 C 函数。这可能只是总线号或设备地址。

或者您可以发挥创造力并且(如 cmets 中所暗示的那样)拥有某种结构,其中包含设备地址或总线号。为此,您需要一个初始化程序,一个以与构造函数等效的方式起作用的函数。您可以将此结构传递给每个 C 函数,就像 OI Sen 所描述的那样。MCP4728 上有各种可用设置(如 VRef 选择、增益和电源状态),因此将这些设置的当前值存储在结构中也是个好主意。

==编辑==

Pygmalion (OP) 找到了一个有用答案的链接,这里是Python ctypes pointer to struct as identifier without member access

另外,将整个事情封装在一个 python 类中可能会很方便,因此您可以使用 __del__ 析构函数来确保自动进行清理。

【讨论】:

  • 当然是MCP4728。我的 C 库具有使用 bitbanging 更改地址的过程和与芯片的标准 I2C 通信。我已经在我的网页上编写并发布了 Python 代码(据我所知,现在只有这样的代码在 Python 中发布)。但是 Python 中的 bitbanging 给出了非常不一致的时间,所以我想让一切都更“专业”,然后再把它放到 github 上。我已经用 C 重写了所有内容,bitbanging 和标准 I2C 通信,并使得两者都可以在 I2C 专用线上完成。
  • 一切都通过 Python 进行了测试并且可以正常工作,我“只是”必须将它包装起来以供公众使用。但这个“公正”可能是最难完成的部分。
  • 我通过创建struct 解决了我的问题,该struct 保存了每个芯片的数据。在初始化时,我使用malloc 创建struct 的新实例,并将指向它们的指针传递回Python。然后 Python 将该指针传递给各个函数。这里有一个描述如何做到这一点:stackoverflow.com/a/62279723/2957687。如果这是您的想法,请将链接添加到您的答案中,我会接受。
  • @Pygmalion 这是一个很好的答案,根据要求在此处添加。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 2011-04-16
  • 2015-11-21
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多