Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How do I free objects after the script execution?#455

AnsweredbyMKostitsyn
MKostitsyn asked this question inQ&A
Discussion options

I have set of scripts that produce and use objects like this:

from pc1 import Pc as pcrb = pc.ReceiptBuilder()# work with receipt builderrb = None

If I comment the last line, rb seems not to be released automatically.
How can this be avoided?
I would like not to have zombie-objects before I run next script.
I also don't like to be forced to release these objects by hands.

You must be logged in to vote

The following code solves my issue. I hope it will be useful for someone else.
fPyDelphiObjects - is a TDictionary<string, PPyObject>, where I keep all the P4D objects, that were created during script execution.
So this code is kinda my own garbage collector.

I would also appreciate to receive any comments on this method, if it has mistakes or vulnerables.

procedure TDeepyPythonModule.ReleasePyObjects;begin  var aScript := TStringList.Create;  try    var aGlobals := GetPythonEngine.EvalString('globals()');    var aKeys := GetPythonEngine.PyDict_Keys(aGlobals);    try      for var I := 0 to GetPythonEngine.PySequence_Length(aKeys) - 1 do      begin        var aKey := GetPythonEngi…

Replies: 7 comments 4 replies

Comment options

Run:
del rb

don't like to be forced to release these objects by hands.

I don't know how to do it automatically

You must be logged in to vote
1 reply
@MKostitsyn
Comment options

rb = None also works fine, but I do want to do it automatically.

In my Delphi project I have list of produced PyObjects, but of course I don't know names of the variables that store them.
Now I think, GlobalVars/LocalVars dictionaries could help me somehow.

Comment options

AFAIRrb = None only zeros the pointer to the var. But value of var is kept.

You must be logged in to vote
0 replies
Comment options

The following code solves my issue. I hope it will be useful for someone else.
fPyDelphiObjects - is a TDictionary<string, PPyObject>, where I keep all the P4D objects, that were created during script execution.
So this code is kinda my own garbage collector.

I would also appreciate to receive any comments on this method, if it has mistakes or vulnerables.

procedure TDeepyPythonModule.ReleasePyObjects;begin  var aScript := TStringList.Create;  try    var aGlobals := GetPythonEngine.EvalString('globals()');    var aKeys := GetPythonEngine.PyDict_Keys(aGlobals);    try      for var I := 0 to GetPythonEngine.PySequence_Length(aKeys) - 1 do      begin        var aKey := GetPythonEngine.PySequence_GetItem(aKeys, I);        if aKey <> nil then        try          var aValue := GetPythonEngine.PyDict_GetItem(aGlobals, aKey);          for var aPair in fPyDelphiObjects do            if aPair.Value = aValue then            begin              var aKeyStr := GetPythonEngine.PyUnicodeAsString(aKey);              aScript.Add('del ' + aKeyStr);              Break;            end;        finally          GetPythonEngine.Py_DECREF(aKey);        end;      end;    finally      GetPythonEngine.Py_xDECREF(aKeys);      GetPythonEngine.Py_xDECREF(aGlobals);    end;    if aScript.Count > 0 then      GetPythonEngine.ExecStrings(aScript);  finally    FreeAndNil(aScript);  end;end;
You must be logged in to vote
0 replies
Answer selected byMKostitsyn
Comment options

here is how to get globals w/o calculating 'globals()'

procedure TAppPython.InitModuleMain;begin  with FEngine do    if ModuleMain=nil then    begin      ModuleMain:= PyImport_AddModule('__main__'); //same as PythonEngine.GetMainModule      if ModuleMain=nil then        raise EPythonError.Create('Python: cannot init __main__');      if GlobalsMain=nil then        GlobalsMain:= PyModule_GetDict(ModuleMain);    end;end;
You must be logged in to vote
1 reply
@MKostitsyn
Comment options

Why is it better? Will it save a lot of resources?

Comment options

also: you call GetPythonEngine 10 times. cache it to var.

You must be logged in to vote
0 replies
Comment options

also:
seehttps://stackoverflow.com/questions/21514631/how-to-delete-an-instantiated-object-python
If i got the idea: running 'del x' is the same as calling DLL API: which decreases ref count. Py_xDECREF .

You must be logged in to vote
1 reply
@MKostitsyn
Comment options

This was my first shot - just to iterate the fPyDelphiObjects dict and to decrease the reference counter, but it lead to the AV in the following scripts when using the same variable.
It seems, Python Engine did not know, that the object was already released.

Comment options

I have set of scripts that produce and use objects like this:

from pc1 import Pc as pcrb = pc.ReceiptBuilder()# work with receipt builderrb = None

If I comment the last line, rb seems not to be released automatically. How can this be avoided? I would like not to have zombie-objects before I run next script. I also don't like to be forced to release these objects by hands.

You can change your code to the following so that you do not pollute the main module dictionary.

defdowork():frompc1importPcaspcrb=pc.ReceiptBuilder()# work with receipt builderdowork()
You must be logged in to vote
1 reply
@MKostitsyn
Comment options

I'm just a beginner in Python.
Is this approach suitable for any possible scenario? For example with local functions/classes/threads, with importing libraries, and so on and so on?

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Category
Q&A
Labels
None yet
3 participants
@MKostitsyn@pyscripter@Alexey-T

[8]ページ先頭

©2009-2025 Movatter.jp