Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.12.11;
Скачать: CL | DM;

Вниз

Странные проблемы с классами   Найти похожие ветки 

 
SkyRanger ©   (2005-11-23 03:54) [0]

Всем привет.
Написал я несколько классов, чтобы облегчить себе работу с модулем Python на делфи...

Вот они:

[code]
{********************************************************}
{                                                        }
{                    pyAPI                               }
{       Copyright (c) 2005 Vasily V. Altunin             }
{                                                        }
{  Разработчик   : Алтунин Василий                       }
{                  (skyr@users.sourceforge.net)          }
{  Модифицирован : 23.11.2005                            }
{  Версия        : 0.01                                  }
{  Вы можете изменять и использовать код приведенный     }
{  ниже на свое усмотрение, при условии сохранения этого }
{  блока.                                                }
{                                                        }
{********************************************************}

unit pyAPI;

interface

uses
 Python, Windows, dialog, SysUtils;

const
 METH_VARARGS  = $0001;
type
 TMethodArray = array[ 0 .. 16000 ] of PyMethodDef;
 PMethodArray = ^TMethodArray;

 TFuncArray = array[ 0 .. 16000 ] of PPyObject;
 TFuncNameArray = array[ 0 .. 16000 ] of PChar;

 TPyMethods = class
 private
   FMethods              : PPyMethodDef;
   FMethodsCount         : Integer;
   FAllocatedMethodCount : Integer;
   FModuleName           : PChar;
   FModuleDoc            : PChar;

   function GetMethod( Index : Integer ) : PPyMethodDef;

 public
   constructor Create(ModuleName, ModuleDoc : PChar);
   destructor Destroy; override;

   function AddMethod( AMethodName : PChar;
                       AMethod  : PyCFunction;
                       ADocString : PChar ) : PPyMethodDef;
   procedure Py_InitModule;

 end;

 TPyScript = class
 private
   FpyName   : PPyObject;
   FpyModule : PPyObject;
   FpyDict   : PPyObject;
 public
   constructor Create(ScriptName:PChar);

   function GetPyModule : PPyObject;
 end;

 TPyFunction = class
 private
   FpyModule           : PPyObject;
   FFuncCount          : Integer;
   FAllocatedFuncCount : Integer;
   FFuncs              : TFuncArray;
   FFuncNames          : TFuncNameArray;
 public
   constructor Create(pyModule : PPyObject);

   function AddFunc( FuncName:PChar ) : PPyObject;
   function GetFuncByName(FuncName:PChar) : PPyObject;
   function CallFuncByName(FuncName:PChar; FuncArgs: PPyObject) : PPyObject;

 end;

Procedure InitPython;
Procedure ExecPythonScript;
Procedure FreePython;

var
 DllHeader     : HModule;
 pyScript      : TPyScript;
 PyMethods     : TPyMethods;
 PyFunction    : TPyFunction;
 PyModule      : PPyObject;

implementation

//====================================================================

constructor TPyMethods.Create(ModuleName, ModuleDoc : PChar);
begin

   FAllocatedMethodCount:=PYT_METHOD_BUFFER_INCREASE;
   FMethodsCount:=0;
   FMethods:=PPyMethodDef(AllocMem(SizeOf(PyMethodDef)*(FAllocatedMethodCount+1)));
   FModuleName:=ModuleName;
   FModuleDoc:=ModuleDoc;
end;

//--------------------------------------------------------------------

destructor TPyMethods.Destroy;
begin
 if Assigned(FMethods) then
 begin
   FMethods := nil;
 end;
 inherited;
end;

//--------------------------------------------------------------------

function TPyMethods.GetMethod( Index : Integer ) : PPyMethodDef;
begin
 Result := @( PMethodArray(FMethods)^[Index] );
end;

function TPyMethods.AddMethod( AMethodName : PChar;
                              AMethod  : PyCFunction;
                              ADocString : PChar ) : PPyMethodDef;
var
 MethodPtr : PPyMethodDef;
begin
 Inc( FAllocatedMethodCount, PYT_METHOD_BUFFER_INCREASE );
 ReAllocMem( FMethods, SizeOf(PyMethodDef)*(FAllocatedMethodCount+1));
 MethodPtr :=@(PMethodArray(FMethods)^[FMethodsCount+1]);
 FillChar( MethodPtr^,SizeOf(PyMethodDef)*PYT_METHOD_BUFFER_INCREASE,0);
 Result:=GetMethod(FMethodsCount);
 Result^.ml_meth:=AMethod;
 Result^.ml_name:=AMethodName;
 Result^.ml_doc:=ADocString;
 Result^.ml_flags := METH_VARARGS;
 Inc(FMethodsCount);
end;

//--------------------------------------------------------------------

procedure TPyMethods.Py_InitModule;
begin
 Py_InitModule4(FModuleName, PyMethods.FMethods,FModuleDoc,nil,1012);
end;

//====================================================================

constructor TPyScript.Create(ScriptName:PChar);
begin
 FpyName   := PyString_FromString(ScriptName);

 FpyModule := PyImport_Import(FpyName);
 Py_DECREF(FpyName);

 FpyDict := PyModule_GetDict(FpyModule);
end;

//--------------------------------------------------------------------

function TPyScript.GetPyModule : PPyObject;
begin
 Result:=FpyModule;
end;


 
SkyRanger ©   (2005-11-23 03:55) [1]


//====================================================================

constructor TPyFunction.Create(pyModule : PPyObject);
begin
   FpyModule:=pyModule;
end;

//--------------------------------------------------------------------

function TPyFunction.AddFunc(FuncName:PChar) : PPyObject;
var
 FuncPtr : PPyMethodDef;
begin
 FFuncNames[FFuncCount]:=FuncName;
 FFuncs[FFuncCount]:=PyObject_GetAttrString(FpyModule,FuncName);
 Inc(FFuncCount);
end;

//--------------------------------------------------------------------

function TPyFunction.GetFuncByName(FuncName:PChar) : PPyObject;
var
 I : Integer;
begin
 for I:=0 to FFuncCount-1 do
   if FFuncNames[I] = FuncName then
     Result := FFuncs[I];
end;

//--------------------------------------------------------------------

function TPyFunction.CallFuncByName(FuncName:PChar; FuncArgs: PPyObject) : PPyObject;
begin
 Result:=PyObject_CallObject(GetFuncByName(FuncName), FuncArgs);
end;

//====================================================================

function Py_Show( self, args : PPyObject ) : PPyObject; cdecl;
begin
     ShowMessage( "args of Show: "+PyString_AsString(PyObject_Str(args)) );
     Result := Py_None;
end;

//====================================================================

Procedure InitPython;
var
 ScriptName : PChar;
 FuncName   : String;
 S          : String;
 pValue     : PPyObject;
begin
 ScriptName:="script";
 FuncName := "multiply";

 PythonInit;

 PyMethods := TPyMethods.Create("Show", "Module Documentation");

 PyMethods.AddMethod("show",Py_Show,"Proc Doc");
 PyMethods.AddMethod("show1",Py_Show,"Proc Doc");
 PyMethods.AddMethod("show2",Py_Show,"Proc Doc");
 PyMethods.AddMethod("show3",Py_Show,"Proc Doc");
 PyMethods.AddMethod("show4",Py_Show,"Proc Doc");

 PyMethods.Py_InitModule;

 PyScript := TPyScript.Create(ScriptName);

 PyModule:=PyScript.GetPyModule;

 PyFunction:= TPyFunction.Create(PyModule);
 PyFunction.AddFunc("OnPaint");
 PyFunction.AddFunc("OnInit");
 PyFunction.AddFunc("OnShow");
 PyFunction.CallFuncByName("OnInit",nil);
 PyFunction.CallFuncByName("OnShow",nil);
 pValue  := PyFunction.CallFuncByName("OnPaint",nil);
 Str(PyInt_AsLong(pValue),S);
 Py_DECREF(pValue);
 ShowMessage( S );
end;

//====================================================================

Procedure ExecPythonScript;
var
 S          : String;
 pValue     : PPyObject;
begin
 pValue  := PyFunction.CallFuncByName("OnPaint",nil);
 Str(PyInt_AsLong(pValue),S);
 Py_DECREF(pValue);
 ShowMessage( S );
end;

//====================================================================

Procedure FreePython;
begin
 PyMethods.Free;
 PyScript.Free;
 PyFunction.Free;
 PythonFree;
end;

//====================================================================

end.


Вот скрипт на питоне который используется для тестирования:


import Show

print Show.__doc__
print Show.__name__

a=3
b=1
print a,b

#Show.show(2,2,2)
#Show.show4(12,12,12)

def OnInit():    
Show.show(1,2,3)
a=3
b=3

def OnShow():    
Show.show(10,20,30)
a=3
b=3
print "111 Will compute", a, "times", b

def OnPaint():    
Show.show(100,200,300)
return 4

Все бы хорошо, если бы не одно НО:

Если я вызываю просто

InitPython;
FreePython;

Все работает как надо, все вызывается и т.д.

Если же я сделаю так:
InitPython;
ExecPythonScript;
FreePython;

Получаю Access Violation на вызове функции:
pValue  := PyFunction.CallFuncByName("OnPaint",nil);

При том даже если я удалю подобный вызов из InitPython;ничего не изменяется :(

По-идее все должно работать, но на практике возникают непонятные проблемы... :(

Скрипт Python.pas вы можете скачать здесь - http://skyr.newmail.ru/Python.pas. Это аналог python.h - импорт функций из .dll питона.


 
Digitman ©   (2005-11-23 08:45) [2]

что показала пошаговая трассировка ?


 
alex_*** ©   (2005-11-23 09:28) [3]

и ты предлагаешь скачать это себе и заняться отладкой?


 
SkyRanger ©   (2005-11-23 09:31) [4]

Ничего!

на function TPyFunction.CallFuncByName(FuncName:PChar; FuncArgs: PPyObject) :
при выполенении:
Result:=PyObject_CallObject(GetFuncByName(FuncName), FuncArgs);

ACCESS VIOLATION и все.

Причем все экземпляры классов никуда не деваются и не изменяются вProcedure ExecPythonScript;
вызов:
pValue  := PyFunction.CallFuncByName("OnPaint",nil);

А тем не менее ошибка появляется...

Причем вызов из процедуры в которой создается экземпляр класса не дает ошибок. Только пи вызове из любого места появляется такая вот ошибка :(

Вот почему так понять не могу...


 
SkyRanger ©   (2005-11-23 09:32) [5]

alex_*** я ничего не предлагаю, а задаю вопрос и надеюсь на ответ, так как я практически все сделал правильно, иначе вообще бы не работало.


 
Digitman ©   (2005-11-23 09:39) [6]


> при выполенении:
> Result:=PyObject_CallObject(GetFuncByName(FuncName), FuncArgs);
>
>
> ACCESS VIOLATION и все.


и что ? "внутренности" этого вызова (GetFuncByName) пошагово разве нельзя пройти ?


 
SkyRanger ©   (2005-11-23 09:44) [7]

Ого...
Очень интересно... По непонятной причине не проходит сравнение на первый взгляд двух одинаковый строк в этой пресловутой функции... Очень странно. Ща буду искать де косяк. У меня такое первый раз...


 
alex_*** ©   (2005-11-23 09:44) [8]

в GetFuncByName сравниваешь указатели, а не содержимое строки. Зачем деражать в TFuncNameArray PChar, не проще string? Посмотри, отрабатывает GetFuncByName(FuncName), или сыпется в нем


 
ЮЮ ©   (2005-11-23 09:44) [9]

А что за зверь такой PyObject_CallObject?


 
alex_*** ©   (2005-11-23 09:46) [10]

с полями типа PChar вообще поосторожней. Я бы заменил поля/типы по возможности с PChar на string


 
SkyRanger ©   (2005-11-23 09:47) [11]

Мдааа...
Маразм крепчал.. Это же PChar и как я понял их низя как простые строки сранивать...

function TPyFunction.GetFuncByName(FuncName:PChar) : PPyObject;
var
I : Integer;
begin
for I:=0 to FFuncCount-1 do
  if String(FFuncNames[I]) = String(FuncName) then
    Result := FFuncs[I];
end;

Теперь вроде работает...
Спасибо всем...


 
SkyRanger ©   (2005-11-23 09:50) [12]

>с полями типа PChar вообще поосторожней. Я бы заменил поля/типы по >возможности с PChar на string

Низя я работаю с функциями импортируемыми из DLL, которая написанна на C++ и чтобы потом не ломать голову почему не работает приходится юзать PChar.

Спасибо за подсказку буду внимательнее...


 
SkyRanger ©   (2005-11-23 09:51) [13]

ЮЮ ©

Если очень интересно то смотри модуль:

http://skyr.newmail.ru/Python.pas

Либо доку по Python - www.python.org


 
alex_*** ©   (2005-11-23 09:52) [14]

вот скажи, зачем ты строки в виде PChar хранишь? Потом в один прекрасный момент начнешь глюки ловить. и уж лучше сравнивать через StrCmp (не помню точно имя, дельфи не стоит)


 
alex_*** ©   (2005-11-23 09:54) [15]

[12] - ну и отлепись чуть от чужой ДЛЛ. скопируй себе строки и работай со своей копией


 
SkyRanger ©   (2005-11-23 10:04) [16]

Всмысле отлепися? исходников на Дельфи нет и не будет. Это интерпритатор питона + куча полезных вещей...


 
alex_*** ©   (2005-11-23 10:10) [17]

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


 
jack128 ©   (2005-11-23 10:30) [18]

SkyRanger ©   (23.11.05 9:50) [12]
Низя я работаю с функциями импортируемыми из DLL, которая написанна на C++ и чтобы потом не ломать голову почему не работает приходится юзать PChar

LOL.  А те не все равно на чем ломать голову - почему не работает при использовании PChar или почему не работает при использовании string ??

И вообще - это полная чушь, что если ипользует dll, писанные С(++), то нельзя использовать string.


 
TUser ©   (2005-11-23 10:40) [19]

А чего такого можно сделать на питоне, чего нельзя на паскале? Чем вызвана необходимость использования всяких экзотических движков?


 
SkyRanger ©   (2005-11-24 01:05) [20]

Например писать скрипт управления сценой 3d движка, описание интерфейса программы на этом движке. Воообще можно сделать много чего интересного. И самое главное не придется пересобирать ядро. Достаточно добавить код в скрипт.

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


 
alex_*** ©   (2005-11-24 09:39) [21]

Ну то что можно не перекомпилять ядро это прикольно, конечно, а быстродействие не страдает?


 
SkyRanger ©   (2005-11-25 03:36) [22]

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



Страницы: 1 вся ветка

Текущий архив: 2005.12.11;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.054 c
2-1133180011
Oni
2005-11-28 15:13
2005.12.11
Вызов функции из модуля, в TurboPascal e


2-1132566744
arkan
2005-11-21 12:52
2005.12.11
База данных (SQL)


14-1132674497
Коновалов Ю.С
2005-11-22 18:48
2005.12.11
Сократ киллер


2-1132841801
Igor_thief
2005-11-24 17:16
2005.12.11
Почему не работает практически идентичный код?


14-1132602645
ArtemESC
2005-11-21 22:50
2005.12.11
Схемы Motherboard ов