6.3. C 模块可变参数

C 模块支持可变参数,使用 *xxx 的输入参数即可,在 C 层会将任意个数的参数打包进 PikaTuple 数据类型中,使用 tuple_getSize() 可以获得可变参数的个数,使用 tuple_getArg() 可以根据可变参数的位置得到 arg。同样支持 tuple_get<Type> api,直接得到指定类型的值。

[注意]

  • 需要内核版本 >= v1.10.0

  • 可变参数必须放在位置参数的后面

示例:

  1. # test.pyi
  2. def vals(a:int, *val):...
  1. // test.c
  2. void test_vals(PikaObj* self, int a, PikaTuple* val){
  3. printf("a: %d\n", a);
  4. for(int i =0; i< tuple_getSize(val); i++){
  5. Arg* arg_i = tuple_getArg(val, i);
  6. printf("val[%d]: %d\n", i, arg_getInt(arg_i));
  7. }
  8. }

输出结果:

  1. >>> test.vals(1, 2, 3, 4)
  2. a: 1
  3. val[0]: 2
  4. val[1]: 3
  5. val[2]: 4
  6. >>>

6.4. C 模块关键词参数

C 模块支持关键词参数,使用 **xxx 的输入参数即可,在 C 层会将任意个数的参数打包进 PikaDict 数据类型中,使用 dict_getArg() 可以根据关键词得到 arg。同样支持 dict_get<Type>() api, 直接得到指定类型的值。

[注意]

  • 需要内核版本 >= v1.10.7

  • 关键词参数必须放在位置参数和可变参数的后面

示例:

  1. # test.pyi
  2. def keys(a:int, **keys):...
  1. // test.c
  2. void test_keys(PikaObj* self, int a, PikaDict* keys){
  3. printf("a: %d\n", a);
  4. printf("keys['b']: %d\n", i, dict_getInt(keys, "b"));
  5. printf("keys['c']: %d\n", i, dict_getInt(keys, "c"));
  6. }

输出结果:

  1. >>> test.keys(1, b=2, c=3)
  2. a: 1
  3. keys['b']: 2
  4. keys['c']: 3
  5. >>>

6.5. C 模块返回 List/Dict

6.5.1. List

  1. # test.pyi
  2. def test_list()->list:...
  1. // test.c
  2. #include "PikaStdData_List.h"
  3. PikaObj* test_test_list(PikaObj* self){
  4. /* 创建 list 对象 */
  5. PikaObj* list = newNormalObj(New_PikaStdData_List);
  6. /* 初始化 list */
  7. PikaStdData_List___init__(list);
  8. /* 用 arg_new<type> 的 api 创建 arg */
  9. Arg* str_arg1 = arg_newStr("aaa");
  10. /* 添加到 list 对象 */
  11. PikaStdData_List_append(list, str_arg1);
  12. /* 销毁 arg */
  13. arg_deinit(str_arg1);
  14. /* 返回列表 */
  15. return list;
  16. }

6.5.2. Dict

注意:需要内核版本 >= v1.10.8

  1. # test.pyi
  2. def test_dict()->dict:...
  1. // test.c
  2. #include "PikaStdData_Dict.h"
  3. PikaObj* test_test_dict(PikaObj* self){
  4. PikaObj* dict = newNormalObj(New_PikaStdData_Dict);
  5. PikaStdData_Dict___init__(dict);
  6. Arg* para1 = arg_newInt(1);
  7. Arg* para2 = arg_newInt(2);
  8. PikaStdData_Dict_set(dict, "para1", para1);
  9. PikaStdData_Dict_set(dict, "para2", para2);
  10. arg_deinit(para1);
  11. arg_deinit(para2);
  12. return dict;
  13. }

6.6. C 模块常量

C 模块支持在类中或模块中加入常量,可以使用 val:type 的语法,这些常量需要在初始化时赋值,因此需要定义 __init__() 方法,例如:

  1. class cJSON:
  2. cJSON_Invalid: int
  3. cJSON_False: int
  4. def __init__(self):...
  5. ...
  1. void pika_cjson_cJSON___init__(PikaObj* self) {
  2. /* const value */
  3. obj_setInt(self, "cJSON_Invalid", cJSON_Invalid);
  4. obj_setInt(self, "cJSON_False", cJSON_False);
  5. ...
  6. }

这些常量可以不创建对象直接使用,即当作类属性来使用。

  1. print(cJSON.cJSON_Invalid)

需要注意的是,PikaScript 的类属性是只读的,对类属性的所有修改都是无效的。

6.7. C 模块初始化

直接在 .pyi 中定义 __init__() 函数即可执行模块初始化,在模块载入时会触发执行,PikaScript 具有模块延时加载机制,import 不会直接触发模块加载,仅仅在第一次真正使用模块时,才会触发加载。

例如:

  1. # test.pyi
  2. def __init__():...
  3. def hello():...
  1. //test.c
  2. void test___init__(PikaObj* self){
  3. printf("now loading module test...\n");
  4. }
  5. void test_hello(PikaObj* self){
  6. printf("hello!\n");
  7. };
  1. # main.py
  2. import test
  3. print('before run test.hello()')
  4. test.hello()
  5. print('after run test.hello()')

输出:

  1. before run test.hello()
  2. now loading module test...
  3. hello!
  4. after run test.hello()