Jump to content
shineworld

Create a property get of 'dict' type

Recommended Posts

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

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

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....

image.thumb.png.ea713b9c0285ec0de5627f8c87208664.png

 

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 by shineworld

Share this post


Link to post

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
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
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 by pyscripter

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×