9.1. Pika 对象 PikaObj

9.1.1. 头文件

#include "PikaObj.h"

9.1.2. 概述

  1. 对象API是以 obj_ 为前缀的一系列函数。

  2. 对象API提供了在 C 中访问 Python 对象的一系列接口。在模块开发中使用频率最高。

  3. 对象API本身也是使用面向对象的思想设计的,这些函数的第一个入口参数都是被操作对象的指针。

  4. 一个对象由属性和方法两个部分组成,因此对象API也分为属性和方法两个部分。

9.1.3. 数据类型

对象本身的数据类型是 PikaObj,所有 Python 对象在 C 中访问时均使用这个数据类型。

struct PikaObj_t {
    /* list */
    Args* list;
};
typedef struct PikaObj_t PikaObj;

PikaObj 内部维护了一个参数表,参数表中包含了属性信息、类信息、方法信息等。 注意不要直接访问 PikaObj 内部的参数表,请使用对象 API 访问 PikaObj。这是因为对象 API 作为对外接口,是长期稳定的,而内部实现则会随着内核代码的迭代经常变动,直接操作 PikaObj 内部将极大损失后向兼容性。

9.1.4. 对象属性API

这一部分 API 提供了对 Python 对象属性的访问。

9.1.4.1. 基本类型的属性

PikaObj 支持整形、浮点型、字串、指针、字节串五种基本类型的属性。使用set 和 get 方法即可读写一个对象的属性。 其中,整形,浮点型,字串和字节串和 python 中的 int, float,string,bytes 一一对应,而指针型则没有对应。

有着对应 python 类型的属性,可以直接在 python 脚本中进行运算和传递,而没有对应的属性,只能在 python 脚本中传递,不能运算。如需要对该属性进行操作,只能将该属性传递到 C 模块中。

对应关系表:

PikaObj 属性类型 读写 API 对应 Python 类型
int obj_setInt() obj_getInt() int
float obj_setFloat() obj_getFloat() float
str obj_setStr() obj_getStr() string
bytes obj_setBytes() obj_getBytes() obj_getBytesSize() bytes
struct obj_setStruct() obj_getStruct() -
pointer obj_setPtr() obj_getPtr() -

PikaObj 的对象是动态的,因此可以随时为对象新增新的属性(静态对象的属性在构造时确定)。

基本类型属性的 API 有如下这些:

/* set API */

int32_t obj_setInt(PikaObj* self, char* argPath, int64_t val);

int32_t obj_setPtr(PikaObj* self, char* argPath, void* pointer);

int32_t obj_setFloat(PikaObj* self, char* argPath, float value);

int32_t obj_setStr(PikaObj* self, char* argPath, char* str);
//create a bytes buff and copy data from 'src'
int32_t obj_setBytes(PikaObj* self, char* argPath, void* src, size_t size);

/* get API */

void* obj_getPtr(PikaObj* self, char* argPath);

float obj_getFloat(PikaObj* self, char* argPath);

char* obj_getStr(PikaObj* self, char* argPath);

int64_t obj_getInt(PikaObj* self, char* argPath);

// get pointer of bytes buff
void* obj_getBytes(PikaObj* self, char* argPath); 
// get size of bytes buff
size_t obj_getBytesSize(PikaObj* self, char* argPath); 
// copy the data from bytes buff to 'out_buff', return the size of memory buff
size_t obj_loadBytes(PikaObj* self, char* argPath, void* out_buff);

基本类型属性的命名方式为 obj_set[Type] 和 obj_get[Type]。

  1. 第一个输入参数为要操作的对象指针。

  2. 第二个输入参数为属性名/属性地址。

PikaObj 支持对象嵌套,可以访问子对象的属性,在访问子对象属性时,第二个参数为属性地址,在访问本对象的属性时,第二个值为属性名。

// set an Int type arg, the arg name is "a".
obj_setInt(self, "a", 1);
// set an Int type arg for subObjcet , the arg path is "subObj.a".
obj_setInt(self, "subObj.a", 1);
  1. set 方法的第三个输入参数为写入的属性值,get 方法的返回值为读取的属性值。

  2. set 方法的返回值为错误码,为 0 表示无错误发生。

9.1.4.2. 泛型属性

PikaObj 支持泛型属性,同样提供 set 方法和 get 方法。输入参数和返回值与基本类型相似。

int32_t obj_setArg(PikaObj* self, char* argPath, Arg* arg);
Arg* obj_getArg(PikaObj* self, char* argPath);

泛型属性在使用时需要转换为基本类型。

使用以下 API 可以判断泛型属性的当前类型。

ArgType arg_getType(Arg* self);

使用以下的 API 可以将泛型属性转换为基本类型。

int64_t arg_getInt(Arg* self);
float arg_getFloat(Arg* self);
void* arg_getPtr(Arg* self);
char* arg_getStr(Arg* self);
void* arg_getBytes(Arg* self);
size_t arg_getBytesSize(Arg* self);

9.1.4.3. 属性管理

  • 判断一个属性是否存在,返回值为 1 表示存在。

int32_t obj_isArgExist(PikaObj* self, char* argPath);
  • 删除一个属性

int32_t obj_removeArg(PikaObj* self, char* argPath);

返回值为错误码,为 0 表示成功。

9.1.5. 对象方法 API

对象方法 API 分为方法注册和方法调用两部分,方法注册部分由预编译器代理,模块开发者只需要使用方法调用 API 即可。

9.1.5.1. 方法调用 API

void obj_run(PikaObj* self, char* cmd);

obj_run 是一个万能的 API,可以直接运行 Python 脚本,并且支持多行脚本。 第一个入口参数是对象的指针,第二个入口参数是字符串形式的 Python 脚本。 要注意的是,传入多行脚本时,应当传入完整的代码块。

9.1.6. 抛出异常

可以在模块中使用 obj_setErrorCode 抛出异常,用户可以自定义异常处理方法(继续运行或停止运行)。 抛出异常通常在 C 模块的方法中使用,传入当前方法的 self 对象指针即可,errCode 设置为非零即可触发异常。 obj_setSysOut 方法常配合 obj_setErrorCode 方法使用,用于提供调试信息,该调试信息会在异常触发时显示在终端。

/* set Error Code, if the errCode is not 0, an exaption would be throw out */
void obj_setErrorCode(PikaObj* self, int32_t errCode);
/* print out exaption infomation */
void obj_setSysOut(PikaObj* self, char* str);