使用C语言扩展Python(五)

简介:
上一篇中我们在python端的做法是每次读取一个数据块,然后将这个数据块传递进C扩展模块中去,但对于目标文件的数据写入是在C扩展模块中完成的,但其实可以更面向对象一点,不是吗?原来outfp是一个文件指针,
不如改成一个从Python中传递一个文件对象到C模块里去,这个文件对象有自己的write方法,这样在C扩展模块中你就可以回调文件对象的write方法来完成数据的写入。
首先来看Python端的代码,我们定义了一个file类继承下来的MyFile子类,其中的write方法就是为在C扩展模块中回调而专门准备的。
复制代码
代码
#!/usr/bin/env python

import clame

INBUFSIZE = 4096

class MyFile(file):

    def __init__(self, path, mode):
        file.__init__(self, path, mode)
        self.n = 0

    def write(self, s):
        file.write(self, s)
        self.n += 1

output = MyFile('test3.mp3', 'wb')
encoder = clame.Encoder(output)
input = file('test.raw', 'rb')

data = input.read(INBUFSIZE)
while data != '':
    encoder.encode(data)
    data = input.read(INBUFSIZE)

input.close()
encoder.close()
output.close()

print 'output.write was called %d times' % output.n
复制代码
  再来看C模块的代码,clame_EncoderObject结构体中的outfp改成了PyObject类型的指针,相应的dealloc方法也做了调整,由于outfp是一个对象,因此需要对其引用计数进行减1操作,而以前的代码是直接调用fclose来直接关闭打开的目标文件。但现在我们只需要对其引用计数做减1操作,等到其为0的时候,在外部的python代码中就可以关闭这个文件对象。同样可以看到在init函数中有相应的引用计数加1的操作。在encode和close两个函数中,通过PyObject_CallMethod实现了对Python对象中指定方法的回调。

复制代码
代码
#include <Python.h>

#include <lame.h>

/*
 * On Linux:
 *   gcc -shared -I/usr/include/python2.6 -I/usr/local/include/lame clame.c \
 *   -lmp3lame -o clame.so
 *
 *
 */

typedef struct {
    PyObject_HEAD
    PyObject *outfp;
    lame_global_flags *gfp;
} clame_EncoderObject;

static PyObject *Encoder_new(PyTypeObject *type, PyObject *args, PyObject *kw) {
    clame_EncoderObject *self = (clame_EncoderObject *)type->tp_alloc(type, 0);
    self->outfp = NULL;
    self->gfp = NULL;
    return (PyObject *)self;
}

static void Encoder_dealloc(clame_EncoderObject *self) {
    if (self->gfp) {
        lame_close(self->gfp);
    }
    Py_XDECREF(self->outfp);
    self->ob_type->tp_free(self);
}

static int Encoder_init(clame_EncoderObject *self, PyObject *args, PyObject *kw) {
    PyObject *outfp;
    if (!PyArg_ParseTuple(args, "O", &outfp)) {
        return -1;
    }
    if (self->outfp || self->gfp) {
        PyErr_SetString(PyExc_Exception, "__init__ already called");
        return -1;
    }
    self->outfp = outfp;
    Py_INCREF(self->outfp);
    self->gfp = lame_init();
    lame_init_params(self->gfp);
    return 0;
}

static PyObject *Encoder_encode(clame_EncoderObject *self, PyObject *args) {
    char *in_buffer;
    int in_length;
    int mp3_length;
    char *mp3_buffer;
    int mp3_bytes;
    if (!(self->outfp && self->gfp)) {
        PyErr_SetString(PyExc_Exception, "encoder not open");
        return NULL;
    }
    if (!PyArg_ParseTuple(args, "s#", &in_buffer, &in_length)) {
        return NULL;
    }
    in_length /= 2;
    mp3_length = (int)(1.25 * in_length) + 7200;
    mp3_buffer = (char *)malloc(mp3_length);
    if (in_length > 0) {
        mp3_bytes = lame_encode_buffer_interleaved(
            self->gfp,
            (short *)in_buffer,
            in_length / 2,
            mp3_buffer,
            mp3_length
        );
        if (mp3_bytes > 0) {
        PyObject* write_result = PyObject_CallMethod(
                                     self->outfp, "write", "(s#)", mp3_buffer, mp3_bytes);
        if (!write_result) {
            free(mp3_buffer);
        return NULL;
        }
        Py_DECREF(write_result);
        }
    }
    free(mp3_buffer);
    Py_RETURN_NONE;
}

static PyObject *Encoder_close(clame_EncoderObject *self) {
    int mp3_length;
    char *mp3_buffer;
    int mp3_bytes;
    if (!(self->outfp && self->gfp)) {
        PyErr_SetString(PyExc_Exception, "encoder not open");
        return NULL;
    }
    mp3_length = 7200;
    mp3_buffer = (char *)malloc(mp3_length);
    mp3_bytes = lame_encode_flush(self->gfp, mp3_buffer, sizeof(mp3_buffer));
    if (mp3_bytes > 0) {
        PyObject* write_result = PyObject_CallMethod(
                                 self->outfp, "write", "(s#)", mp3_buffer, mp3_bytes);
    if (!write_result) {
        free(mp3_buffer);
        return NULL;
    }
    Py_DECREF(write_result);
    }
    free(mp3_buffer);
    lame_close(self->gfp);
    self->gfp = NULL;
    self->outfp = NULL;
    Py_RETURN_NONE;
}

static PyMethodDef Encoder_methods[] = {
    { "encode", (PyCFunction)Encoder_encode, METH_VARARGS,
          "Encodes and writes data to the output file." },
    { "close", (PyCFunction)Encoder_close, METH_NOARGS,
          "Closes the output file." },
    { NULL, NULL, 0, NULL }
};

static PyTypeObject clame_EncoderType = {
    PyObject_HEAD_INIT(NULL)
    0,                             /* ob_size */
    "clame.Encoder",             /* tp_name */
    sizeof(clame_EncoderObject), /* tp_basicsize */
    0,                             /* tp_itemsize */
    (destructor)Encoder_dealloc,   /* tp_dealloc */
    0,                             /* tp_print */
    0,                             /* tp_getattr */
    0,                             /* tp_setattr */
    0,                             /* tp_compare */
    0,                             /* tp_repr */
    0,                             /* tp_as_number */
    0,                             /* tp_as_sequence */
    0,                             /* tp_as_mapping */
    0,                             /* tp_hash */
    0,                             /* tp_call */
    0,                             /* tp_str */
    0,                             /* tp_getattro */
    0,                             /* tp_setattro */
    0,                             /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,            /* tp_flags */
    "My first encoder object.",    /* tp_doc */
    0,                             /* tp_traverse */
    0,                             /* tp_clear */
    0,                             /* tp_richcompare */
    0,                             /* tp_weaklistoffset */
    0,                             /* tp_iter */
    0,                             /* tp_iternext */
    Encoder_methods,               /* tp_methods */
    0,                             /* tp_members */
    0,                             /* tp_getset */
    0,                             /* tp_base */
    0,                             /* tp_dict */
    0,                             /* tp_descr_get */
    0,                             /* tp_descr_set */
    0,                             /* tp_dictoffset */
    (initproc)Encoder_init,        /* tp_init */
    0,                             /* tp_alloc */
    Encoder_new,                   /* tp_new */
    0,                             /* tp_free */
};

static PyMethodDef clame_methods[] = {
    { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initclame() {
    PyObject *m;
    if (PyType_Ready(&clame_EncoderType) < 0) {
        return;
    }
    m = Py_InitModule3("clame", clame_methods, "My third LAME module.");
    Py_INCREF(&clame_EncoderType);
    PyModule_AddObject(m, "Encoder", (PyObject *)&clame_EncoderType);
}
复制代码



本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2010/05/23/1742344.html,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
Unix 编译器 Shell
[oeasy]python0033_先有操作系统还是先有编程语言_c语言是怎么来的
本文回顾了计算机语言与操作系统的起源,探讨了早期 Unix 操作系统及其与 C 语言的相互促进发展。Unix 最初用汇编语言编写,运行在 PDP-7 上,后来 Thompson 和 Ritchie 开发了 C 语言及编译器,使 Unix 重写并成功编译。1974 年 Ritchie 发表论文,Unix 开始被学术界关注,并逐渐普及。伯克利分校也在此过程中发挥了重要作用,推动了 Unix 和 C 语言的广泛传播。
71 9
[oeasy]python0033_先有操作系统还是先有编程语言_c语言是怎么来的
|
15天前
|
Unix 编译器 C语言
[oeasy]python052_[系统开发语言为什么默认是c语言
本文介绍了C语言为何成为系统开发的首选语言,从其诞生背景、发展历史及特点进行阐述。C语言源于贝尔实验室,与Unix操作系统相互促进,因其简洁、高效、跨平台等特性,逐渐成为主流。文章还提及了C语言的学习资料及其对编程文化的影响。
24 5
|
1月前
|
缓存 监控 测试技术
Python中的装饰器:功能扩展与代码复用的利器###
本文深入探讨了Python中装饰器的概念、实现机制及其在实际开发中的应用价值。通过生动的实例和详尽的解释,文章展示了装饰器如何增强函数功能、提升代码可读性和维护性,并鼓励读者在项目中灵活运用这一强大的语言特性。 ###
|
3月前
|
Python
Python--turtle库科赫雪花的扩展
使用Python的turtle库创建科赫雪花,并加入随机阶数、尺寸、位置和颜色的功能,每次运行生成不同图像。
Python--turtle库科赫雪花的扩展
|
2月前
|
机器学习/深度学习 缓存 PyTorch
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
这篇文章是关于如何下载、安装和配置Miniconda,以及如何使用Miniconda创建和管理Python环境的详细指南。
550 0
pytorch学习一(扩展篇):miniconda下载、安装、配置环境变量。miniconda创建多版本python环境。整理常用命令(亲测ok)
|
2月前
|
机器学习/深度学习 物联网 数据处理
C语言用于物联网更合适还是python
选择 C 语言还是 Python 作为物联网(IoT)开发的语言取决于多个因素,包括项目的性质、资源限制、性能需求以及开发团队的技能水平。C 语言性能优越,适合资源受限的嵌入式设备,能直接访问硬件,广泛应用于底层开发,但开发复杂且容易出错。Python 则以其简单的语法和丰富的库支持快速开发和原型制作,适合跨平台应用和数据处理,但性能较低,资源占用较大。根据项目需求,性能和资源要求高时选择 C 语言,需快速开发和易于维护时选择 Python。
|
2月前
|
Python
Python扩展TimedRotatingFileHandler
【10月更文挑战第7天】 python log执行扩展压缩功能
63 0
|
2月前
|
编译器 C语言
初识C语言:扩展世界观,选择语句之行
初识C语言:扩展世界观,选择语句之行
|
3月前
|
存储 缓存 API
比较一下 Python、C、C 扩展、Cython 之间的差异
比较一下 Python、C、C 扩展、Cython 之间的差异
54 0
|
3月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)