Python for Delphi problem
Greg Chapman
glc at well.com
Tue Feb 11 10:51:31 EST 2003
You have to be more careful about your refcounting.
>procedure TForm1.Button1Click(Sender: TObject);
>var
> pyName, pyModule, pyDict, pyList, pyItem : PPyObject;
> Index, pyListSize : Integer;
> Item, TempItem : PChar;
>begin
> {import moddule}
> pyName := PythonEngine1.PyString_FromString( PChar(Edit1.Text) );
> pyModule := PythonEngine1.PyImport_Import(pyName);
>
> if pyModule <> nil then
> begin
> {Get the modules dictionary}
> pyDict := PythonEngine1.PyModule_GetDict(pyModule);
> {Get the keys list from the dictionary}
> pyList := PythonEngine1.PyDict_Keys(pyDict);
> {Get the size of the list}
> pyListSize := PythonEngine1.PyList_Size(pyList);
>
> {Allocate space for a string to hold the results}
> Item := StrAlloc(21);
You dont't need to do this; it would be much better to declare Item as a
string (AnsiString); Delphi automatically converts null-terminated PChars to
strings when assigned. Python ensures that the char * buffer is
null-terminated.
>
> for Index := 0 to pyListSize do
> begin
> {Get each item in the list}
> pyItem := PythonEngine1.PyList_GetItem(pyList, Index);
> {Convert the item to a null terminated string}
> TempItem := PythonEngine1.PyString_AsString(pyItem);
> {Copy to the new Item string}
> StrLCopy(Item, TempItem, 20);
> PythonEngine1.Py_DECREF(pyItem);
> pyItem := nil;
> ListBox1.Items.Add(String(Item));
> PythonEngine1.Py_DECREF(pyList);
^^^ the above is the same as freeing the list -- you don't want to do
this in the middle of a loop which is accessing it!
> end;
> PythonEngine1.Py_DECREF(pyModule);
> end;
> PythonEngine1.Py_DECREF(pyName);
>end;
>
In general, I'd introduce some try finally blocks to ensure that references are
properly DECREF'd. I assume the PythonEngine supports the equivalent of
Py_XDECREF (which checks for a NULL pointer before DECREFing). If so, you could
change the above to:
procedure TForm1.Button1Click(Sender: TObject);
var
pyName, pyModule, pyDict, pyList, pyItem : PPyObject;
Index, pyListSize : Integer;
TempItem: PChar;
begin
pyModule:= nil; pyList:= nil;
pyName := PythonEngine1.PyString_FromString( PChar(Edit1.Text) );
if pyName = nil then
Exit; {raise exception}
try
{import moddule}
pyModule := PythonEngine1.PyImport_Import(pyName);
if pyModule = nil then
Exit; {raise exception}
{Get the module's dictionary}
pyDict := PythonEngine1.PyModule_GetDict(pyModule);
{Get the keys list from the dictionary}
pyList := PythonEngine1.PyDict_Keys(pyDict);
{Get the size of the list}
pyListSize := PythonEngine1.PyList_Size(pyList);
for Index := 0 to pyListSize-1 do
begin
{Get each item in the list}
pyItem := PythonEngine1.PyList_GetItem(pyList, Index);
if pyItem = nil then
Break; {raise exception}
try
TempItem:= PyString_AsString(pyItem);
if TempItem = nil then
Break; {raise exception}
{use implicit conversion of PChar to string}
ListBox1.Items.Add(TempItem);
finally
PythonEngine1.Py_DECREF(pyItem);
end;
end;
finally
PythonEngine1.Py_XDECREF(pyList);
PythonEngine1.Py_XDECREF(pyModule);
PythonEngine1.Py_DECREF(pyName);
end;
end;
---
Greg Chapman
More information about the Python-list
mailing list