如何在Delphi中使用C API函数PyArg_ParseTupleAndKeywords?

3 投票
1 回答
536 浏览
提问于 2025-04-18 03:23

我现在正在用 python4delphi 写一个Python模块。我想使用标准的C语言API函数 PyArg_ParseTupleAndKeywords

从文档中可以看到,这个函数的用法是这样的:

int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format,
    char *keywords[], ...)

现在这个函数在python4delphi中没有封装,所以我自己添加了它:

PyArg_ParseTupleAndKeywords: function (args, kw: PPyObject; format: PAnsiChar; 
    keywords: array of PAnsiChar {;...}): Integer; cdecl varargs;
....
PyArg_ParseTupleAndKeywords := Import('PyArg_ParseTupleAndKeywords');

我遇到的问题是,当我尝试像下面这个代码片段那样使用它时,出现了访问违规的错误:

function PyScript_MyFunction(pself, args, keywds : PPyObject) : PPyObject; cdecl;
var
  AAA, BBB : PChar;
  kwlist : array[0..2] of PAnsiChar;
begin
  kwlist[0] := 'AAA';
  kwlist[1] := 'BBB';
  kwlist[2] := nil;

  BBB := 'BBB';
  with GetPythonEngine do
  begin
    if (PyErr_Occurred() = nil) and (PyArg_ParseTupleAndKeywords(args, keywds,
        's|s:Script_MyFunction', kwlist, @AAA, @BBB) <> 0) then
    begin
      Result := VariantAsPyObject(MyFunction(AAA, BBB));
    end
    else
      Result := nil;
  end;
end;

//Module is my Python module I am working with

Module.AddMethodWithKeywords('Wrapped', @PyScript_MyFunction, 'no doc');

我该如何解决这个问题?有没有办法调试这种错误?

1 个回答

4

你对keywords参数的理解不太正确。你用了Delphi的开放数组。Delphi的开放数组会传递两个东西,一个是数组最后一个元素的索引,另一个是数组第一个元素的指针。其实,Delphi的开放数组根本不应该用来进行跨语言调用。

你需要这样声明这个参数:

keywords: PPAnsiChar

这实际上是一个指向PAnsiChar的指针。

调用这个函数时应该这样:

PyArg_ParseTupleAndKeywords(..., @kwlist[0], ...) 

我个人建议使用动态数组来准备你的参数:

var
  kwlist: TArray<PAnsiChar>;

初始化时可以这样做:

kwlist := TArray<PAnsiChar>.Create('AAA', 'BBB', nil);

然后这样传递它:

PPAnsiChar(kwlist)

或者如果你更喜欢这样:

@kwlist[0]

后者至少是类型安全的。


我注意到你把AAABBB声明为PChar类型。其实应该是PAnsiChar


我不太确定你是否正确准备了其他所有参数。我对这个特定的API调用不太熟悉。不过,以上我提到的内容是你需要首先解决的最重要的问题。

我还想知道,作为调用者,你是如何处理返回给你的字符串的?我想你应该负责处理这些字符串。

撰写回答