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

Answered by pyscripter
MKostitsyn asked this question in Q&A
Discussion options

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

from pc1 import Pc as pc
rb = pc.ReceiptBuilder()
# work with receipt builder
rb = 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

If you want to clean up your created global variables, the best way is to use the following ExecString/EvalString overloads:

 procedure ExecString(const command: AnsiString; locals, globals: PPyObject; const FileName: string = '<string>'); overload;
 function EvalString(const command: AnsiString; locals, globals: PPyObject; const FileName: string = '<string>'): PPyObject; overload;

and provide a new locals dictionary (PyDict_New), which you destroy (Py_DECREF) after the calling the above functions.

Note that if globals is nil, it becomes the same as locals.

Replies: 8 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
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

AFAIR rb = 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
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
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:
see https://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
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 pc
rb = pc.ReceiptBuilder()
# work with receipt builder
rb = 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.

def dowork():
 from pc1 import Pc as pc
 rb = pc.ReceiptBuilder()
 # work with receipt builder
dowork()
You must be logged in to vote
1 reply
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?

Comment options

If you want to clean up your created global variables, the best way is to use the following ExecString/EvalString overloads:

 procedure ExecString(const command: AnsiString; locals, globals: PPyObject; const FileName: string = '<string>'); overload;
 function EvalString(const command: AnsiString; locals, globals: PPyObject; const FileName: string = '<string>'): PPyObject; overload;

and provide a new locals dictionary (PyDict_New), which you destroy (Py_DECREF) after the calling the above functions.

Note that if globals is nil, it becomes the same as locals.

You must be logged in to vote
0 replies
Answer selected by pyscripter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /