首页 > 解决方案 > 如何在python C-api中解析所需的互斥参数

问题描述

如何使用 python C-api 解析一组必需但互斥的参数?

例如给定函数定义

static PyObject* my_func(PyObject *self, PyObject *args, PyObject *kwargs)  {
   double a;          // first argument, required 
   double b=0, c=0;   // second argument, required but mutually exclusive, b is default keyword if no keyword is set
   char d[] = "...";  // third argument, optional

   // parse arguments
   ...
}

我的想法是两次解析输入参数,即将...上面替换为:

   static const char *kwList1[] = {"a","b","c","d"};
   static const char *kwList2[] = {"a","b","d"};
   int ret;
   if (!(ret = PyArg_ParseTupleAndKeywords(args,kwargs,"d|dds",(char **)kwList1,&a,&b,&c,&d))) {
      ret = PyArg_ParseTupleAndKeywords(args,kwargs,"d|ds",(char **)kwList2,&a,&b,&d));
   }
   if (!ret) return NULL;

   // verify that one of, but not both, variables b and c are non-zero
   ...

但是,对于有效输入,第二次调用PyArg_ParseTupleAndKeywords()返回 0,所以我在这里假设变量argskwargs具有由第一次调用设置的一些属性PyArg_ParseTupleAndKeywords()导致第二次调用失败(输出 python 错误是:TypeError:需要浮点数)。

我知道可以使用argparsepython 模块解决上述问题,但更喜欢直接使用 C-api 的解决方案。这里的一个想法是,如果有可能首先将输入复制 到args两个kwargsPyObject变量中,然后在第二次调用PyArg_ParseTupleAndKeywords()如何释放为此分配的内存)。

标签: pythoncargumentsmutual-exclusion

解决方案


似乎问题在于第一次调用PyArg_ParseTupleAndKeywords()设置错误指示器导致第二次调用函数失败。所以解决方案是在对 的调用PyErr_Clear()之间插入一个调用PyArg_ParseTupleAndKeywords()。总之,以下代码执行任务

static PyObject* my_func(PyObject *self, PyObject *args, PyObject *kwargs)  {
   double a;          // first argument, required 
   double b=0, c=0;   // second argument, required but mutually exclusive, b is default keyword if no keyword is set
   char d[] = "...";  // third argument, optional

   // parse arguments
   static const char *kwList1[] = {"a","b","c","d"};
   static const char *kwList2[] = {"a","b","d"};
   int ret;
   if (!(ret = PyArg_ParseTupleAndKeywords(args,kwargs,"d|dds",(char **)kwList1,&a,&b,&c,&d))) {
      PyErr_Clear();
      ret = PyArg_ParseTupleAndKeywords(args,kwargs,"d|ds",(char **)kwList2,&a,&b,&d));
   }
   if (!ret) return NULL;

   // verify that one of, but not both, variables b and c are non-zero
   if (b==0 && c==0) {
      PyErr_SetString(PyExc_TypeError,"Required mutually exclusive arguments 'b' or 'c' (pos 2) not found (or input with value 0)");
      return NULL;
   } else if (b!=0 && c!=0) {
      PyErr_SetString(PyExc_TypeError,"Use of multiple mutually exclusive required arguments 'b' and 'c' (pos 2)");
      return NULL;
   }

   ...

}

再一次,这并不能防止使用两个参数调用函数,b并且c假设其中一个是 0 而另一个不是。然而,这是一个小问题。


推荐阅读