Reputation: 6137
I'm trying to convert Python function to Delphi using Python4Delphi (to educate myself and to gain speed, I hope). However I've no idea how this works with Delphi and Python. Here's my original function:
def MyFunc(img, curve):
C = 160
for i in xrange(img.dim()[0]):
p = img[i]
img[i] = (p[0], p[1], p[2] - curve[p[0]] + C)
(Img is not python list, but custom object)
I found related Demo09 from Python4Delphi, but couldn't find any help how to go thru that list, unpack the tuple and modify value.
Any pointers for documentation creating extensions?
Upvotes: 3
Views: 3758
Reputation: 69012
Python4Delphi handles the problem of loading Python's main DLL into a Delphi program, embedding the Python interpreter into your delphi application, but also has some demos for the reverse; to write an extension using Delphi. Below is some working example code.
I found a book book reference here to writing python extensions using delphi. Page 469 of the Python Programming on Win32, by Mark Hammond & Andy Robinson (O'Reilly).
A sample DLL skeleton for a Delphi DLL that implements a python extension might look like this, taken from the Demo09 folder in Python4Delphi source distribution:
Project (.dpr) file source:
library demodll;
{$I Definition.Inc}
uses
SysUtils,
Classes,
module in 'module.pas';
exports
initdemodll;
{$IFDEF MSWINDOWS}
{$E pyd}
{$ENDIF}
{$IFDEF LINUX}
{$SONAME 'demodll'}
{$ENDIF}
begin
end.
Actual extension unit (module.pas):
unit module;
interface
uses PythonEngine;
procedure initdemodll; cdecl;
var
gEngine : TPythonEngine;
gModule : TPythonModule;
implementation
function Add( Self, Args : PPyObject ) : PPyObject; far; cdecl;
var
a, b : Integer;
begin
with GetPythonEngine do
begin
if PyArg_ParseTuple( args, 'ii:Add', [@a, @b] ) <> 0 then
begin
Result := PyInt_FromLong( a + b );
end
else
Result := nil;
end;
end;
procedure initdemodll;
begin
try
gEngine := TPythonEngine.Create(nil);
gEngine.AutoFinalize := False;
gEngine.LoadDll;
gModule := TPythonModule.Create(nil);
gModule.Engine := gEngine;
gModule.ModuleName := 'demodll';
gModule.AddMethod( 'add', @Add, 'add(a,b) -> a+b' );
gModule.Initialize;
except
end;
end;
initialization
finalization
gEngine.Free;
gModule.Free;
end.
Note that methods that can be called from python can only have parameters Self, Args : PPyObject
as their parameter signature, and the Args value is a Python tuple (an immutable data structure similar to a vector or array). You then have to parse the tuple, and inside it, there will be 1 or more arguments of various types. You then have to deal with the fact that each item inside the tuple object passed in could be an integer, a string, a tuple, a list, a dictionary, etc etc.
You're going to need to learn to call method on a python object as in python code: img.dim()
, get items from a list and so on.
Look for whereever PyArg_ParseTuple
is defined (ctrl-click it) and look for other methods that start with the prefix Py
that might have names like PyList_GetItem
. That is the pseudo-OOP naming convention used by python (PyCATEGORY_MethodName
). It's all pretty easy once you see some sample code. Sadly, most of that sample code is in C.
You could probably even use a tool to auto-convert your Python code above into sample C code, then try translating it into Python, line by line. But it all sounds like a waste of time to me.
Some more Python API functions to look up and learn:
Py_BuildValue
- useful for return values
Py_INCREF
and Py_DECREF
- necessary for object reference counting.
You will need to know all the memory rules, and ownership rules here.
Upvotes: 8