Python4Delphi — Ошибка при переносе интерфейса delphi с помощью TPyDelphiWrapper.WrapInterface

#python #delphi #python4delphi

#python #delphi #python4delphi

Вопрос:

Я использую Python 3.8 с Delphi 10.4.2.

Я пытаюсь использовать компоненты Python4Delphi для доступа через скрипт Python к некоторым интерфейсам, определенным в Delphi.

Во время разработки я добавил компоненты TPythonEngine, TPythonModule и TPyDelphiWrapper в форму VCL моего проекта.

Итак, я определил 3 интерфейса, реализованных 3 классами соответственно, как показано ниже

 type
  IPerson = interface (IUnknown)
    ['{1D21B5B6-25DE-4884-8BDB-8E2D9A239D64}']
    function GetName : string;
    procedure SetName ( value : string );
    property Name: string read GetName write SetName;   
    function GetSurname: string;
    procedure SetSurname(value : string);
    property Surname : string read GetSurname write SetSurname;    
    function GetInfo : string;
  end;

  ICustomer = interface (IPerson)
    ['{8742364C-33E8-4FF4-86FB-C19AF67A735B}']
    function GetCustomerNumber : string;
    procedure SetCustomerNumber ( value : string );
    property CustomerNumber : string read GetCustomerNumber write SetCustomerNumber;
  end;

  ISupplier = interface ( IPerson )
    ['{420FFF78-92DE-4D7E-9958-FDA95748EEB7}']
    function GetSupplierNumber : string;
    procedure SetSupplierNumber ( value : string );
    property SupplierNumber : string read GetSupplierNumber write SetSupplierNumber;
  end;

  TPerson = class ( TInterfacedObject , IPerson)
  private
    FName : string;
    FSurname : string;    
    function GetName : string;
    procedure SetName ( value : string );    
    function GetSurname: string;
    procedure SetSurname(value : string);

  public
    property Surname : string read GetSurname write SetSurname;
    property Name: string read GetName write SetName;    
    function GetInfo : string; virtual;
  end;


  TCustomer = class ( TPerson , ICustomer)
  private
    FCustomerNumber : string;
    function GetCustomerNumber : string;
    procedure SetCustomerNumber ( value : string);

  public    
    property CustomerNumber : string read GetCustomerNumber write SetCustomerNumber;
    function GetInfo: string; override;
  end;


  TSupplier = class ( TPerson , ISupplier)
  private
    FSupplierNumber : string;
    function GetSupplierNumber : string;
    procedure SetSupplierNumber ( value : string );

  public
    property SupplierNumber : string read GetSupplierNumber write SetSupplierNumber;
    function GetInfo : string; override;
  end;
 

В методе Create формы я определил 3 переменные, по одной для каждого из 3 интерфейсов, и через PyDelphiWrapper я передал их в модуль Python в 3 разных переменных Python.

 procedure TFrmTestInterface.FormCreate(Sender: TObject);
var
  LPerson : IPerson;
  LCustomer : ICustomer;
  LSupplier : ISupplier;
  Py: PPyObject;
begin

  LPerson := TPerson.Create;
  LCustomer := TCustomer.Create;
  LSupplier := TSupplier.Create;

  LPerson.Name := 'Pippo';
  LPerson.Surname := 'Rossi';

  LCustomer.Name := 'Pluto';
  LCustomer.Surname := 'Verdi';

  LSupplier.Name := 'Paperino';
  LSupplier.Surname := 'Bianchi';


  Py := PyDelphiWrapper1.WrapInterface(TValue.From(LPerson));
  PythonModule1.SetVar('delphi_person', Py);
  GetPythonEngine.Py_DecRef(Py);

  Py := PyDelphiWrapper1.WrapInterface(TValue.From(LCustomer));
  PythonModule1.SetVar('delphi_customer', Py);
  GetPythonEngine.Py_DecRef(Py);

  Py := PyDelphiWrapper1.WrapInterface(TValue.From(LSupplier));
  PythonModule1.SetVar('delphi_supplier', Py);
  GetPythonEngine.Py_DecRef(Py);

end;
 

Во время выполнения переменные интерпретируются правильно, но каждый раз, когда я пытаюсь получить доступ к одному из свойств, определенных в интерфейсе, я всегда получаю одну и ту же ошибку.

Это скрипт Python, который я пытаюсь запустить:

 from delphi_module import delphi_person, delphi_customer, delphi_supplier 

print('type(delphi_person) = ', type(delphi_person)) 
print('type(delphi_customer) = ', type(delphi_customer)) 
print('type(delphi_supplier) = ', type(delphi_supplier)) 

print(delphi_person.Name)
 

И ошибка, которую я получаю

Обратная трассировка (последний последний вызов): файл «», строка 7, в AttributeError: ошибка при получении свойства «Name». Ошибка: Неизвестный атрибут

Команда type(…) выполняется правильно для трех переменных.

Если вместо использования 3 переменных типа интерфейса я объявляю каждую переменную как тип класса, используя PyDelphiWrapper .Метод переноса, все работает правильно!

 procedure TFrmTestInterface.FormCreate(Sender: TObject);
var
  LPerson : IPerson;
  LCustomer : ICustomer;
  LSupplier : ISupplier;
  Py: PPyObject;
begin

  LPerson := TPerson.Create;
  LCustomer := TCustomer.Create;
  LSupplier := TSupplier.Create;

  LPerson.Name := 'Pippo';
  LPerson.Surname := 'Rossi';

  LCustomer.Name := 'Pluto';
  LCustomer.Surname := 'Verdi';

  LSupplier.Name := 'Paperino';
  LSupplier.Surname := 'Grandi';


  Py := PyDelphiWrapper1.Wrap(LPerson, TObjectOwnership.soReference);
  PythonModule1.SetVar('delphi_person', py);
  GetPythonEngine.Py_DECREF(py);

  Py := PyDelphiWrapper1.Wrap(LCustomer, TObjectOwnership.soReference);
  PythonModule1.SetVar('delphi_customer', py);
  GetPythonEngine.Py_DECREF(py);

  Py := PyDelphiWrapper1.Wrap(LSupplier, TObjectOwnership.soReference);
  PythonModule1.SetVar('delphi_supplier', py);
  GetPythonEngine.Py_DECREF(py);

end;
 

С помощью того же скрипта Python я получаю правильный вывод без ошибок

введите описание изображения здесь

У кого-нибудь есть идеи, что я делаю не так с использованием TPyDelphiWrapper для переноса переменных типа интерфейса для скриптов Python?

Комментарии:

1.Вдали от компьютера atm. Я думаю, вам нужно создать экземпляры ваших интерфейсов и передать их. Тестовый код использует: FTestInterface := TTestInterfaceImpl.Create; Py := PyDelphiWrapper.WrapInterface(TValue.From(FTestInterface));

Ответ №1:

Delphi не добавляет RTTI к свойствам, определенным в интерфейсах. Поэтому движок Python не может найти свойство ‘Name’. RTTI доступен для методов, когда вы добавляете {$M } перед объявлением интерфейса. Вызываю delphi_person.Тогда getName() должен работать.

Существует еще одна проблема с использованием интерфейсов и движка Python, интерфейс не блокируется при вызове WrapInterface. Поэтому объект будет выпущен, когда он выйдет за пределы области видимости.