

marcelsema
Members-
Content Count
5 -
Joined
-
Last visited
Everything posted by marcelsema
-
Hello everyone, I am looking to destroy an object once it is no longer referenced in python. I am struggeling to correctly do this. unit Unit1; interface uses SysUtils, Classes, Windows, Messages, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, PythonEngine, Vcl.PythonGUIInputOutput, WrapDelphi; type TForm1 = class(TForm) Splitter1: TSplitter; Memo1: TMemo; PythonEngine1: TPythonEngine; PythonModule1: TPythonModule; Panel1: TPanel; Button1: TButton; PythonGUIInputOutput1: TPythonGUIInputOutput; Memo2: TMemo; PyDelphiWrapper1: TPyDelphiWrapper; procedure Button1Click(Sender: TObject); private public destructor Destroy; override; function GetDelphiWrapper: TPyDelphiWrapper; function GetPythonEngine: TPythonEngine; end; TEntry = class(TObject) strict private FstrName: string; FclsStringList: TStringList; public constructor Create(strName: string); destructor Destory; function Name: string; end; TManager = class(TObject) public function GetNewEntry: PPyObject; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var clsManager: TManager; pyManager: PPyObject; begin clsManager := TManager.Create; pyManager := PyDelphiWrapper1.Wrap(clsManager, soReference); PythonModule1.SetVar( 'manager', pyManager ); PythonEngine1.ExecStrings( memo1.Lines ); PythonEngine1.Py_DecRef(pyManager); end; { TManager } function TManager.GetNewEntry: PPyObject; begin // I want TEntry to be destroyed by python once it is no longer used Result := Form1.GetDelphiWrapper.Wrap(TEntry.Create('Test'), soOwned); Form1.GetPythonEngine.Py_DECREF(Result); end; destructor TForm1.Destroy; begin FreeAndNil(PythonModule1); FreeAndNil(PythonEngine1); inherited; end; function TForm1.GetDelphiWrapper: TPyDelphiWrapper; begin Result := PyDelphiWrapper1; end; function TForm1.GetPythonEngine: TPythonEngine; begin Result := PythonEngine1; end; { TEntry } constructor TEntry.Create(strName: string); begin inherited Create; FclsStringList := TStringList.Create; FstrName := strName; end; destructor TEntry.Destory; begin FreeAndNil(FclsStringList); inherited; end; function TEntry.Name: string; begin Result := FstrName; end; end. from spam import * entry = manager.GetNewEntry() print(entry.Name()) After clicking the button, I get an exception accessing an invalid pointer. I also tried returning the object directly instead of wraping it to a PPyObject, but that did not work. Thank you for your help. Best regards, Marcel
-
omg I am so sorry -.- Thx for spotting the issue. I assume https://github.com/pyscripter/python4delphi/discussions/455#discussioncomment-7974673 is the solution for this. Thank you very much for your time! Best regards, Marcel
-
Unit1.zip Thank you for taking a look at it.
-
Interesting. I am unable to get this to work. I adjusted the python script, removed the Py_DECREF and no destructor is called. Is it also possible to clean up variables after the ExecStrings? unit Unit1; interface uses SysUtils, Classes, Windows, Messages, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, PythonEngine, Vcl.PythonGUIInputOutput, WrapDelphi; type TForm1 = class(TForm) Splitter1: TSplitter; Memo1: TMemo; PythonEngine1: TPythonEngine; PythonModule1: TPythonModule; Panel1: TPanel; Button1: TButton; PythonGUIInputOutput1: TPythonGUIInputOutput; Memo2: TMemo; PyDelphiWrapper1: TPyDelphiWrapper; procedure Button1Click(Sender: TObject); private public destructor Destroy; override; function GetDelphiWrapper: TPyDelphiWrapper; function GetPythonEngine: TPythonEngine; end; TEntry = class(TObject) strict private FstrName: string; FclsStringList: TStringList; public constructor Create(strName: string); destructor Destory; function Name: string; end; TManager = class(TObject) public function GetNewEntry: PPyObject; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var clsManager: TManager; pyManager: PPyObject; begin try clsManager := TManager.Create; pyManager := PyDelphiWrapper1.Wrap(clsManager, soReference); PythonModule1.SetVar( 'manager', pyManager ); PythonEngine1.ExecStrings( memo1.Lines ); PythonEngine1.Py_DecRef(pyManager); finally FreeAndNil(clsManager); end; end; { TManager } function TManager.GetNewEntry: PPyObject; begin // I want TEntry to be destroyed by python once it is no longer used Result := Form1.GetDelphiWrapper.Wrap(TEntry.Create('Test'), soOwned); //Form1.GetPythonEngine.Py_DECREF(Result); end; destructor TForm1.Destroy; begin FreeAndNil(PythonModule1); FreeAndNil(PythonEngine1); inherited; end; function TForm1.GetDelphiWrapper: TPyDelphiWrapper; begin Result := PyDelphiWrapper1; end; function TForm1.GetPythonEngine: TPythonEngine; begin Result := PythonEngine1; end; { TEntry } constructor TEntry.Create(strName: string); begin inherited Create; FclsStringList := TStringList.Create; FstrName := strName; end; destructor TEntry.Destory; begin FreeAndNil(FclsStringList); inherited; end; function TEntry.Name: string; begin Result := FstrName; end; end. object Form1: TForm1 Left = 214 Top = 174 Width = 592 Height = 422 VertScrollBar.Range = 210 ActiveControl = Memo1 Caption = 'Form1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = 11 Font.Name = 'MS Sans Serif' Font.Pitch = fpVariable Font.Style = [] TextHeight = 13 object Splitter1: TSplitter Left = 0 Top = 113 Width = 576 Height = 3 Cursor = crVSplit Align = alTop ExplicitTop = 169 end object Memo1: TMemo Left = 0 Top = 116 Width = 576 Height = 226 Align = alClient Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -13 Font.Name = 'Consolas' Font.Pitch = fpVariable Font.Style = [] Lines.Strings = ( 'from spam import *' '' 'entry = manager.GetNewEntry()' 'print(entry.Name())' 'entry = None') ParentFont = False ScrollBars = ssVertical TabOrder = 0 WordWrap = False ExplicitWidth = 570 ExplicitHeight = 209 end object Panel1: TPanel Left = 0 Top = 342 Width = 576 Height = 41 Align = alBottom BevelOuter = bvNone TabOrder = 1 ExplicitTop = 325 ExplicitWidth = 570 object Button1: TButton Left = 8 Top = 8 Width = 75 Height = 25 Caption = 'Execute' TabOrder = 0 OnClick = Button1Click end end object Memo2: TMemo Left = 0 Top = 0 Width = 576 Height = 113 Align = alTop Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -13 Font.Name = 'Consolas' Font.Pitch = fpVariable Font.Style = [] ParentFont = False TabOrder = 2 ExplicitWidth = 570 end object PythonEngine1: TPythonEngine DllPath = 'D:\temp\PythonPkg' IO = PythonGUIInputOutput1 Left = 48 Top = 24 end object PythonModule1: TPythonModule Engine = PythonEngine1 ModuleName = 'spam' Errors = < item Name = 'PointError' ErrorType = etClass end item Name = 'EBadPoint' ErrorType = etClass ParentClass.Name = 'PointError' end> Left = 152 Top = 24 end object PythonGUIInputOutput1: TPythonGUIInputOutput UnicodeIO = True RawOutput = False Output = Memo2 Left = 376 Top = 24 end object PyDelphiWrapper1: TPyDelphiWrapper Engine = PythonEngine1 Module = PythonModule1 Left = 248 Top = 24 end end
-
Hey, Thank you for your answer. The problem why I included Form1.GetPythonEngine.Py_DECREF(Result); is that TEntry.Destory is otherwise never called and I just want TEntry destroyed after I executed the script. You are right, clsManager gets leaked. I assume that I have to look into DEMO32 for the correct way to use the WrapDelphi ? Best regards, Marcel