Wrapping Delphi Objects
If you have an existing object in Delphi that you'd like to use in Python but you don't want to modify that object to make it Python-aware, then you can wrap that object just for the purposes of supplying it to python.
As an example, if you have an existing Delphi class called Color:
TRGBColor = class
private
fRed, fGreen, fBlue: Integer;
public
property Red: read fRed write fRed;
property Green: read fGreen write fGreen;
property Blue: read fBlue write fBlue;
end;
You want to use Color within some Python code but you don't want to change anything about the class. So you make a wrapper that provides some very basic services, such as getting and setting attributes of a Color, and getting a string representation:
TPyColor = class(TPyObject)
private
fColor: TRGBColor;
public
constructor Create( APythonType : TPythonType ); override;
// Basic services
function GetAttr(key : PChar) : PPyObject; override;
function SetAttr(key : PChar; value : PPyObject) : Integer; override;
function Repr : PPyObject; override;
end;
implementation
constructor TPyColor.Create( APythonType : TPythonType );
begin
inherited;
fColor := nil;
end;
function TPyColor.GetAttr(key : PChar) : PPyObject;
begin
if key = "Red" then
result := GetPythonEngine.VariantAsPyObject(fColor.Red)
else if key = "Green" then
result := GetPythonEngine.VariantAsPyObject(fColor.Green)
else if key = "Blue" then
result := GetPythonEngine.VariantAsPyObject(fColor.Blue)
else
result := inherited GetAttr(key);
end;
function TPyColor.SetAttr(key : PChar; value : PPyObject) : Integer;
begin
result := 0;
if key = "Red" then
fColor.Red := Integer(GetPythonEngine.PyObjectAsVariant(value))
else if key = "Green" then
fColor.Green := Integer(GetPythonEngine.PyObjectAsVariant(value))
else if key = "Blue" then
fColor.Blue := Integer(GetPythonEngine.PyObjectAsVariant(value))
else
result := inherited SetAttr(key, value);
end;
function TPyColor.Repr : PPyObject;
begin
end;
As you can see, the wrapper object accepts Python code getting and setting certain attributes and it simply passes these on to its internal fColor instance.
Now we must have a way to pass our wrapper object to Python. We create a Python dictionary for the local variables that our Python code can access, and add our TPyColor to it.
// Given a Python dictionary, add an instance of TRGBColor. This code
// could be separated into different functions for your own purposes. Use the
// dictionary by passing it into PythonEngine's PyRun_String as the 'locals'
// parameter.
function AddColor(py_dict: PPyObject; var_name: string; c: TRGBColor);
var
t: TPythonType;
pyc: TPyColor;
pyc_value: PPyObject;
begin
// Set up TPyColor's type within the Python engine.
t := TPythonType.Create(GetSandboxEngine);
t.Engine := GetPythonEngine;
t.Name := 'PythonTRGBColor';
t.TypeName := typename;
t.Prefix := 'Create';
t.Services.Basic := bsGetAttr, bsSetAttr, bsRepr;
t.TypeFlags := result.TypeFlags + tpfBaseType;
t.PyObjectClass := TPyColor;
t.Initialize;
// Create a new instance of the type in the Python engine.
pyc_value := t.CreateInstance;
// Add the instance we created under the given variable name.
GetPythonEngine.PyDict_SetItemString(py_dict, PChar(var_name), pyc_value);
GetPythonEngine.Py_DECREF(pyc_value); // Important. Give the instance solely to Python.
// Set the Python instance of TPyColor to our TRGBColor
pyc := PythonToDelphi(pyc_value) as TPyColor;
pyc.fColor := c;
end;
This is how you would set up the local dictionary that needs to be passed to AddMyColor :
procedure RunPyCode;
var
locals: PPyObject;
c: TRGBColor;
begin
// Create the local variable dictionary.
locals := GetPythonEngine.PyDict_New;
try
// Make the color blue.
c := TRGBColor.Create;
c.Red := 0; c.Green := 0; c.Blue := 255;
// Add our color to the local variables.
AddColor(locals, 'my_color', c);
// Run some code that uses TRGBColor.
GetPythonEngine.PyRun_String(PChar('all = my_color.Red + my_color.Green + my_color.Blue'),
file_input,
GetPythonEngine.PyModule_GetDict(GetPythonEngine.GetMainModule),
locals);
finally
Py_XDECREF(fLocals_py);
end;
end;
Comments (0)
You don't have permission to comment on this page.