在自定义C模块中使用Python模块的C API
这看起来有点像我想要的,不过我想在另一个C模块中创建一个C的PyObject实例。
用C API创建一个在Python中声明的Python类的实例
但是我找不到关于如何从C使用Python模块的文档。网上的资料大多数都在讲如何用C扩展Python。
我的问题是,我有一个Pygame项目,我想加快它的速度。所以我正在制作一个C模块,需要访问Pygame。我该如何导入pygame呢?我可不想导入两个副本,对吧?代码部分我能搞定,但我就是不知道怎么配置和链接这些代码。我知道我一定漏掉了一些文档,如果有人能指点我一下,我会非常感激。
更新:抱歉,我重新读了一下我的帖子,发现我的措辞很糟糕。
如果你安装了pygame,可以去你的Python/include目录下找pygame的头文件。它们是干什么用的?我以为你的C模块可以直接访问pygame的C模块,这样你的Python脚本和C模块就能使用同一个pygame实例。
有人能帮我澄清一下吗?
3 个回答
我在网上搜索了一下,结果点了一个“我很幸运”的链接。
你可以使用pygame的C接口,尽管这可能不是它本来的用途(这就引出了一个问题,为什么pygame的头文件会和pygame包一起安装)。
如果你用这种“内部”接口构建的扩展,可能在下一个版本或构建的pygame发布时会出现问题,除非pygame的开发者关注这些C头文件的接口兼容性...
总之,这里有一个例子:
C扩展模块代码(red.c):
#include <Python.h>
#include <pygame/pygame.h>
static PyObject* fill_surface(PyObject* self, PyObject* args)
{
PyObject* py_surface = NULL;
if( !PyArg_ParseTuple(args, "O", &py_surface) )
return NULL;
PySurfaceObject* c_surface = (PySurfaceObject*) py_surface;
SDL_FillRect( c_surface->surf, 0, SDL_MapRGB(c_surface->surf->format, 255, 0, 0) );
return Py_None;
}
PyMethodDef methods[] = {
{"fill_surface", fill_surface, METH_VARARGS, "Paints surface red"},
{NULL, NULL, 0, NULL},
};
void initred()
{
Py_InitModule("red", methods);
}
用于构建的Makefile(Linux):
SOURCES = red.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = red.so
CFLAGS += -Wall -O2 -g
CFLAGS += $(shell python-config --cflags)
CFLAGS += $(shell sdl-config --cflags)
LDFLAGS += $(shell sdl-config --libs)
all: $(TARGET)
clean:
$(RM) $(OBJECTS)
$(RM) $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) -shared -o $@ $(OBJECTS) $(LDFLAGS)
$(OBJECTS): Makefile
Python测试代码:
import pygame
import red
pygame.init()
screen = pygame.display.set_mode( (640, 480) )
red.fill_surface(screen)
pygame.display.update()
pygame.time.delay(3000)
这个技巧就是用C语言来写普通的Python程序。你可以使用一些特定的函数,比如 PyImport_ImportModule()
来导入模块,PyObject_GetAttr()
来获取对象的属性,以及 PyObject_Call()
来调用对象的方法,具体使用哪个要根据情况来决定。