Harriv
Harriv

Reputation: 6137

Creating Python extension with Delphi

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

Answers (1)

Warren  P
Warren P

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

Related Questions