shineworld 73 Posted April 20, 2023 Hi all, I would like to add, to a python4delphi module, a getter method which return a 'dict'. For example: > import pycnccore1 as pyc >cnc_core = pyc.CNCCore() >print(cnc_core.paths) {'user_path': 'c:\\xyz', 'machine_path': 'd:\\machine_test', and so on} I don't know how to create a Delphi type to contain the dictionary and convert it to a Python dict as a result of the getter method. function TPyCNCCore.GetPaths(AContext: Pointer): PPyObject; begin Adjust(@Self); var PathDict: <i_do_not_know>; PathDict.Append('user_path', Self.UserPathString); PathDict.Append('machine_path', Self.MachinePathString); ... and so on ... Result := GetPythonEngine.VariantAsPyObject(PathDict); end; class procedure TPyCNCCore.RegisterGetSets(PythonType: TPythonType); begin inherited; with PythonType do begin PythonType.AddGetSet('paths', @TPyCNCCore.GetPaths, nil, 'Returns the used paths', nil); end; end; Thanks in advance for your suggestions Silverio Share this post Link to post
David Heffernan 2345 Posted April 20, 2023 Do you want to create a new instance of Python dict every time the property is called? Or aren't you looking to implement the Python mapping protocol so that Python has something that behaves like a dict, but actually just reflects the underlying Delphi object? Share this post Link to post
shineworld 73 Posted April 20, 2023 (edited) In other projects, I've used the automatic conversion of Delphi classes to related Python wrapper classes. In this project, I would like manually create the python module classes using low-level python implementation. Looking at P4D WrapFireDac.pas code I saw a way to manually create a dictionary. Seems to work but is hard to know when to apply Py_XDecRef.... function TPyCNCCore.GetPaths(AContext: Pointer): PPyObject; var Key: PPyObject; Value: PPyObject; PathsDict: PPyObject; Engine: TPythonEngine; procedure AddItem(const K, V: string); begin Key := Engine.VariantAsPyObject(Variant(K)); Value := Engine.VariantAsPyObject(Variant(V)); Engine.PyDict_SetItem(PathsDict, Key, Value); Engine.Py_XDecRef(Key); Engine.Py_XDecRef(Value); end; begin Adjust(@Self); Engine := GetPythonEngine; PathsDict := Engine.PyDict_New; AddItem('MachineBackupPath', Self.FCNCManager.MachineBackupPath); AddItem('MachineCustomizePath', Self.FCNCManager.MachineCustomizePath); AddItem('MachineMacrosPath', Self.FCNCManager.MachineMacrosPath); AddItem('MachineMediaPath', Self.FCNCManager.MachineMediaPath); AddItem('MachinePath', Self.FCNCManager.MachinePath); AddItem('MachineRunPath', Self.FCNCManager.MachineRunPath); AddItem('MachineVmPath', Self.FCNCManager.MachineVmPath); AddItem('SamplesPath', Self.FCNCManager.SamplesPath); AddItem('UserDataPath', Self.FCNCManager.UserDataPath); Result := PathsDict; end; I don't know if this is the right way to 'return' a dict in a getter method.. In my ignorance of the subject, I am navigating by sight. Should be cool a direct way to convert a TDictionary to Python dict. Edited April 20, 2023 by shineworld Share this post Link to post
David Heffernan 2345 Posted April 20, 2023 Consider a large dictionary with, for sake of argument, 1 million items in it. Suppose in Python you wanted to write value = foo[name] Now if foo was actually in your Delphi code, and backed by a Delphi dictionary, do you really want to populate a new Python dict with 1 million items, then perform the lookup in Python, and then throw away that dictionary. Wouldn't it be better to just ask Delphi to perform the lookup. This is what I mean what I talk about the mapping protocol. But it's entirely possible that I have misunderstood what you actually want to do! Share this post Link to post
shineworld 73 Posted April 20, 2023 3 minutes ago, David Heffernan said: Considera un grande dizionario con, per amor di discussione, 1 milione di voci al suo interno. Supponiamo che in Python tu voglia scrivere valore = foo[nome] Ora, se foo fosse effettivamente nel tuo codice Delphi e supportato da un dizionario Delphi, vuoi davvero popolare un nuovo dict Python con 1 milione di elementi, quindi esegui la ricerca in Python e poi butta via quel dizionario. Non sarebbe meglio chiedere a Delphi di eseguire la ricerca. Questo è ciò che intendo di ciò che parlo del protocollo di mappatura. Ma è del tutto possibile che io abbia frainteso ciò che realmente vuoi fare! Ah ok, I completely misrepresented your previous sugestions. So it would make more sense to do a normal GetPath(name) method that returns the value instead of returning a dictionary with all the variables 🙂 It makes sense Thanks for the suggestion Share this post Link to post
pyscripter 689 Posted April 20, 2023 (edited) 48 minutes ago, shineworld said: Seems to work but is hard to know when to apply Py_XDecRef.... See Passing a python object to a delphi function parameter - Python4Delphi - Delphi-PRAXiS [en] (delphipraxis.net) Edited April 20, 2023 by pyscripter Share this post Link to post
David Heffernan 2345 Posted April 20, 2023 @pyscripter do you know if it's reasonable to implement the python mapping protocol on the Delphi side so that from python it looks like a Python mapping? Share this post Link to post
pyscripter 689 Posted April 20, 2023 (edited) 1 hour ago, David Heffernan said: @pyscripter do you know if it's reasonable to implement the python mapping protocol on the Delphi side so that from python it looks like a Python mapping? Yes indeed! P4D makes it quite easy. The TStrings wrapper does that for instance. Edited April 20, 2023 by pyscripter Share this post Link to post