| Home | Products | Downloads | Order | Support 

Python for Delphi is a set of free components that wrap up the Python Dll into Delphi. They let you easily execute Python scripts, create new Python modules and new Python types. You can create Python extensions as Dlls and much more.
Version 3.32 (Oct 14, 2006)
  • Added support for loading the Python 2.5.
    I had to disable the following 2 APIs which are not exported anymore: PyRange_New and PySymtableEntry_Type.
    I removed the exception PyExc_OverflowWarning.
    I added EPyBaseException exception and changed the hierarchy to reflect latest changes:
    BaseException # New in Python 2.5
    |- KeyboardInterrupt
    |- SystemExit
    |- Exception
       |- (all other current built-in exceptions)
  • Introduced a potential breaking change to P4D: the conditional symbol PREFER_UNICODE is now defined by default. Which means that any string stored in a variant will be converted to a Python unicode string.
    If you don't want that, then make sure that this symbol is not defined in definition.inc
    Note also that PyString_Check has been modified to accept unicode strings. If you want to discriminate, use PyString_CheckExact.
  • Kiriakos made changes to TPythonInputOutput to allow wide strings in I/O and thus support international chars. It introduces 2 news events OnSendUniData/OnReceiveUniData. This new behaviour will be activated only if you define the PREFER_UNICODE symbol and set the new UnicodeIO property.
  • Added TPythonEngine.Type_CheckExact(), done by Kiriakos.
  • Fixed bug into the new callback allocator thanks to Samuel Iseli. In some very rare cases, the empty space of a memory page was wrong and could crash the application.
  • Fixed a bug into TPythonEngine.PyObject_AsVariant that prevented a date to be converted to a real date variant. It was considered as a float, thanks to Oliver Bock [oliver@g7.org].
  • Fixed a bug in TPythonEngine.PyObjectAsString when the submitted object is a unicode string.
  • Added api PySeqIter_New to TPythonEngine
  • Added api PyObject_CallMethodStr and PyObject_CallMethodWithArgs to TPythonEngine thanks to Dietmar Budelsky.
  • Added methods Repaint and Invalidate to the TControl wrapper
  • Added package files for C++Builder 6 thanks to Philippe BOURGAULT
  • Created a Wiki at http://py4d.pbwiki.com/ thanks to a suggestion of Oliver Bock
    This will allow any person involved with P4D to collaborate on building a useful documentation (at last ;-)
  • Added methods ClientToScreen and ScreenToClient to the TControl wrapper thanks to Joachim.
  • Added changes made by Samuel Iseli to WrapDelphiGrids:
    I added an indexed property for setting column widths (ColWidths[i]) and methods to get / set cell contents of stringgrid to the gridwrapper.
    I thought it was easier to do the cell get/set with separate methods GetCell(col,row), SetCell(col, row, value) instead of trying to imitate the Delphi 2dim array property (Cells[col, row]).
  • Made fields fDefaultIterType and fDefaultContainerType of TPyDelphiWrapper protected as a request made by Samuel Iseli.
  • Added new property "Version" to TPythonEngine returning the current version of P4D as a string as a request made by Roar Larsen.

Version 3.31 (Mar 14, 2006)
  • Added support for Delphi 2006
  • Updated WrapDelphi:
    • Wrapped TPageControl
    • Wrapped TTabSheet
  • Fixed a very rare but nasty bug thanks to Samuel Iseli - Vertec AG [samuel.iseli@vertec.ch] On some Windows Server 2003 machines, a P4D application using custom Types or Modules would crash. After investigation, Samuel found out that this was related to a Bios feature that would prevent code from running when the code was located on a memory page that was not flagged as executable. This was the case for all the generated callbacks that would wrap Delphi methods. After looking at Borland's solution regarding the MakeObjectInstance code we knew that we had do a VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE). Samuel wrote a simple memory allocator using pages of virtual alloc, and replaced the old GetMem/FreeMem calls. And we could also get rid of the list of created callbacks as we have now our own custom allocator, which should speed up application's exit as we can free pages instead of blocks.
  • Simplified PythonEngine.pas to take into account an excellent suggestion of Samuel Iseli: the TPythonType was registering callbacks for each type's service, where the type's method would simply forward the work to the TPyObject instance. Instead of using callbacks, we can now use simple static functions which should also speed up a P4D application a little.
  • Added version 1.5 of PyScripter source code.

Version 3.30 (Dec 18, 2005)
  • Added function VarModuleHasObject to VarPyth.pas (done by Dietmar) to check if a module contains a specific object.
  • Fixed Bug in P4D that would prevent a script from printing unicode strings.
  • Made breaking change to TPythonEngine: the pyio module which is used to redirect input/output is not imported any more (pyio = __import__("pyio")) to avoid polluting the list of imported module (change made by Kiriakos Vlahos).
  • Included new release 1.3 of PyScripter source code.
  • Updated WrapDelphi:
    • Added new unit WrapDelphiWindows (to define a couple of symbols only)
    • Added new unit WrapDelphiComCtrls
    • Added new unit WrapDelphiGrids
    • Added new unit WrapDelphiGraphics
    • Added new unit WrapDelphiButtons
    • Wrapped TSize
    • Wrapped TCanvas, TGraphic, TBitmap, TMetaFile, TIcon, TPicture
    • Wrapped TKeyPressEvent, TKeyEvent
    • Made a breaking change when dealing with property sets:
      now we expect a sequence of strings. Each string should have the name as the enumeration in the set.
      Ex: MainForm.Anchors = ['akLeft', 'akTop']
      Of course, a set property will now return a list of strings.
      In the past, it would have returned an integer containing all the bits of the set, and it would have accepted to assign either the same kind of integer value or a string like "[akLeft, akTop]".
    • Made a breaking change when dealing with property enumerations:
      return a string representing its value instead of the ordinal value.
    • You don't need to call explicitely RegisterClass for your registered Python types as it will be done automatically for you in RegisterDelphiWrapper. But it is still usefull if you need to create VCL objects that have no wrapper, using the CreateComponent helper function.
    • Thanks to Fabio Chelly who used WrapDelphi, reported errors and contributed.

Version 3.29 (Aug 28, 2005)
  • Fixed bug in TPythonType, reported by Roar Larsen [roar@tordivel.no], where a Access Violation would occur when exceeding 10 methods/getsets/members in a new base type (tpfBaseType option).

  • Fixed bug found by daydaysy [ildg@163.com] where VarIsPythonClass would return False when checking a new style Python class inheriting from object (class Foo(object): pass).

  • Used exported API for function PyImport_ExecCodeModule instead of duplicating code

  • Added APIs PyObject_GetIter, PyIter_Next and PyIter_Check to TPythonEngine

  • Added changes sent by Chris Nicolai :
    added PyThreadState_SetAsyncExc -- throw an exception into _another_ thread!!
    added new PyThreadState members from Python2.3

  • Addew new virtual class procedure SetupType to TPyObject, allowing the class to setup its associated Python type. This is very useful when building a hierarchy of classes, and thus avoiding copy&paste of the type services for each TPythonType. Instead, setup the type in the base class, and introduce in the subclasses the new services when they're implemented.

  • Added methods AddMethodWithKeywords/AddDelphiMethodWithKeywords to TPythonModule and TPythonType, allowing you to create functions receiving keyword parameters: foo(param1=val1, param2=val2...)

  • Added function VarPythonIsIterator to VarPyth.pas (and rewrote functions len and iter)

  • Added new component TPyDelphiWrapper originally written and donated by Kiriakos Vlahos [kvlahos@london.edu] It allows you to interact with Delphi VCL objects from Python. It works with Delphi5 or above. It also helps expose your own Delphi classes to Python more easily with Delphi 7 or later.
    Look at the documentation embedded at the beginning of the WrapDelphi.pas unit.

  • Added Demos 31 and 32 that show how you can benefit from WrapDelphi.

  • Added support for Free Pascal Compiler (http://www.freepascal.org/) and Lazarus Project (http://www.lazarus.freepascal.org/)
    Thanks to Michiel du Toit (micdutoit@hsbfn.com)

  • Added new folder "Modules" containing the folder "Delphi" which contains a Dll project for building a Python .pyd module in order to expose the VCL to a regular Python interpreter. Modules also constains a very simple Python script relying on Delphi.pyd for displaying a simple form.
    Note that you must ensure that Delphi.pyd is accessible from the Python path, before trying to run TestApp.py

  • Updated source code of PythonIDE (PyScripter) to reflect latest 1.2 version.

Version 3.28 (Apr 23, 2005)
  • Fixed a bug in PyObjectAsVariant thanks to Kiriakos Vlahos [kvlahos@london.edu]
    Testing for Boolean values should be done before Integer values, as Boolean inherit from Integers.
  • Fixed a bug in ArrayToPyTuple, ArrayToPyList and ArrayToPyDict when giving empty string as argument thanks to Dietmar Budelsky.

  • Added demo29 showing how to exchange images between Delphi and Python Imaging Library (PIL).
  • In PythonEngine.pas, added APIs:
    • PyObject_Call
    • PyErr_SetInterrupt
  • Added new feature to VarPyth: you can now invoke functions or methods using named parameters.
    A big advantage of named parameters over regular parameters is that the order of parameters is not important
    and help invoking functions with many optional parameters, as you can only specify the one you need.
    Note that any Python function can be invoked with or without named parameters, and that you can mix regular and named parameters.

    Python code:
    	def MakeList(a, b, c):
    	  return [a, b, c]

    Delphi code:
      	  _main : Variant;
    	  L : Variant;
    	  _main := MainModule;
    	  L := _main.MakeList(1, 2, 3); // L = [1, 2, 3] (this is the old way)
    	  L := _main.MakeList(1, c := 3, b := 2); // L = [1, 2, 3] Note that you can mix 
    	                                          // regular and named parameters.
    	  L := _main.MakeList(c := 3, a := 1, b := 2); // L = [1, 2, 3] Only named parameters
  • Added Demo30 to show how you can use named parameters.
  • Added Project PythonIDE thanks to a donation of Kiriakos Vlahos [kvlahos@london.edu].
    PyScripter was not designed to compete with other Python IDE tools but rather to serve the purpose of providing a strong scripting
    solution for Delphi Applications. However it is a reasonably good stand-alone Python IDE.


    • Easy Integration with Delphi applications
    • Syntax Highlighting
    • Brace Highlighting
    • Python source code utilities ((un)tabify, (un)comment, (un)indent)
    • Code Explorer
    • File Explorer with filter
    • Easy configuration and browsing of the Python Path
    • Access to Python manuals through the Help menu and context sensitive help (press F1 on a Python keyword inside the editor)
    • Integrated Python Interpreter
    • Command History
    • Alt-UP : previous command
    • Alt-Down : next command
    • Esc : clear command
    • Code Completion
    • Call Tips
    • Integrated Python Debugging
    • Debug Windows
    • Call Stack
    • Variables Window
    • Watches Window
    • BreakPoints Window
    • Modern UI with docked forms
    • Persistent configurable IDE options
    Note that P4D only contains PythonIDE source code, but you can download a compiled version from

    If you want to rebuild it by yourself, you'll need to look at PythonIDE\Readme.txt for the required
    component packages.
  • Flagged GetAtom of PythonAtom.pas and TAtomPythonEngine of AtomPythonEngine.pas as deprecated when using Delphi 6 or later.
    You should replace TAtomPythonEngine by TPythonEngine and PythonAtom.pas by VarPyth.pas.
    Note that VarPyth and PythonAtom act differently. So, simply changing the unit may compile but your application may crash at runtime because PythonAtom converts Python sequences into variant arrays for instance, whereas VarPyth will keep the Python sequence object and let you act on it.
    See discussions in the yahoo group and Andy's tutorial about latest techniques:

    Converting TAtomPythonEngine is easy: open the form or datamodule hosting the component, View as text (Alt + F12), replace TAtomPythonEngine by TPythonEngine, View as Form (Alt + F12), in the unit, replace TAtomPythonEngine by TPythonEngine nad replace AtomPythonEngine by PythonEngine (in the uses).

    Note that eventhough you get a deprecated warning, it still works as it is and you're not required to do the change.
    It's only better to do it for the future and for the additional benefits of VarPyth...

  • Updated file 'Deploying P4D.pdf' to refer to the Python tool that helps collect all module dependencies.

Version 3.27 (Dec 5, 2004)
  • added method flush when redirecting IO. This was fix made by Qi Wenmin (dumm@libr.3322.org):
    In my work I find a little problem with the RedirectIO feature. I enable the RedirectIO and add a stream handler of logging package to the logger. When I launch the script in Delphi, the engine reports the stream handler has no flush() method. So I make some change with PythonEngine.pas, add the following codes into the code constant in the TPythonEngine.DoRedirectIO method.
  • fixed a bug when the datetime module was not deployed, P4D would raise an exception while executing RedirectIO.
  • added new event OnSysPathInit to TPythonEngine. This event is fired immediately after Py_Initialize and will provide the list object stored in sys.path, containing all the folders used by Python to find an imported module.
    This will allow you to extend the path when you have a custom installation that is not allowed to touch the windows registry/filesystem.
    procedure TForm1.PythonEngine1SysPathInit(Sender : TObject; PathList : PPyObject);
      folder : PPyObject;
      with GetPythonEngine do
        folder := PyString_FromString('c:\myapp\mymodules');
        PyList_Append(PathList, folder);
  • fixed a bug: when using a Python iterator, eventhough you caught the stop exception, a 'Stop iteration' message was displayed in the output.
  • added function iter to VarPyth.pas that will return an iterator object for the specified container argument.
      _iter : Variant;
      _value : Variant;
      _iter := iter(VarPythonCreate([1, 2, 3, 4], stTuple));
        while True do
          _value := iter.next();
        on E: EPyStopIteration do
          // End of sequence
  • added PyDict_Copy api
  • added overloaded ExecStrings/EvalStrings methods that let you provide your own global/local dictionaries.
    Note that you can still use the TPythonEngine properties LocalVars and GlobalVars.
  • added demo27 showing the possibilities of container indexing:
    #extended slice
    #multidimensional slice:
    s[10, 10:20, 20:100:5, ...]
  • added demo28 showing how to implement an iterator over a sequence (a simple TStringList wrapper)
  • added support for Delphi 2005

Version 3.26 (Sep 6, 2004)
  • Added compatibility with new version 2.4 of Python (Alpha presently)
  • Added new document "Deploying P4D.PDF" explaining how you can deploy your own version of Python (using a private folder).
  • Fixed a bug in PythonEngine.pas: when trying to convert a variant containing an empty string to a Python object, the application could crash with a Memory error exception.
  • Fixed a small memory leak when instanciating TPythonEngine at runtime, without an Owner, then TPythonEngine would leak and internal TPythonModule used for redirecting I/O. (thanks to t.handler@n-tree.com)
  • Fixed a problem in demo 16 / Example 1 (missing a __str__ override in the wrapper class)

Version 3.25 (Apr 5, 2003)
  • Added compatibility with Python 2.3b2 that refactored the new datetime module.
  • Allowed TPyObject instances to be created without a TPythonType, in order to use them outside
    P4D context (give nil as argument). This is a suggestion made by Gert Steyn [gert@ise.co.za]
  • Fixed a bug in TPythonType.TypeFlagsAsInt where some flags where forgotten (tpfHeapType, tpfBaseType, tpfReady, tpfReadying, tpfHaveGC) thanks to jacoboy1234 [fan_jacob@hotmail.com]
  • Added APIs PyObject_GenericGetAttr, PyObject_GenericSetAttr, PyType_GenericAlloc, PyType_GenericNew, PyType_Ready, PyObject_Free
  • Added new class TMembersContainer allowing TPythonType to define members of a type and added class method RegisterMembers to TPyObject, allowing type objects to define their members, to be used when subclassing an existing type.
  • Added new class TGetSetContainer allowing TPythonType to define properties with Get/Set accessor functions, and added class method RegisterGetSets to TPyObject, allowing type objects to define their properties, to be used when subclassing an existing type.
  • Allowed any TPythonType (and related TPyObject class) to become a base type that may be subclassed within Python.
    To use this feature, simply select tpfBaseType in the TypeFlags property of TPythonType, then override TPyObject.RegisterMembers in your Python/Delphi class and expose each of your instance member as a MemberDef (call AType.AddMember(...)).
    You can override TPyObject.RegisterGetSets in you need to expose properties with Get/Set accessor functions.

    You should not override GetAttr and SetAttr anymore and you should not select the Basic services flags [bsGetAttr, bsSetAttr].
    Instead, simply select the flags [bsGetAttrO, bsSetAttrO] and the class TPyObject does simply call PyObject_GenericGetAttr in GetAttrO
    and PyObject_GenericSetAttr in SetAttrO.
    The Python Generic Get/Set functions will use new slots introduced in the type object for specifying a list of members (class fields), a list of get/set functions (like properties in Delphi) and a list of methods. That way a subclass can introduce its own members/get,set/methods and call the others coming from the base classes.

    You can override the new Init method of TPyObject if you want to perform the same kind of initialization that you would do in the __init__ method of a Python class.
    Note however that by default the CreateWith constructor of TPyObject will be called when instanciating a new subtype, allowing you to get constructor arguments as you already did with regular types.

    Note that for a subtype instance, the memory allocated will come from Python heap and not from Delphi. So, we have a reserved space inside the subtype
    instance where we plug our Delphi class definition. This is tricky but it works!

    Note that TPyObject now has a new attribute IsSubType set to True when a subtype is instanciated.

    Note that if tpfBaseType is set, you can now instanciate a type by calling its type object instead of relying on the CreateXXX function. Ex: p = spam.Point(3, 2)
    In that case Python acts as it would create a subtype instance by using the tp_new slot of your type, but the type pointer given is the one of your TPythonType.
    So, your TPyObject instance will have memory allocated by Python (prop PythonAlloc is true) and the property IsSubType will be set to False.

    Note that to enable this double behaviour, I had to change the way a TPyObject is allocated: I removed the first two fields (ob_refcnt and ob_type) and replaced them with public properties, and redefined NewInstance and FreeInstance to allocate a bigger chunk of memory (with Sizeof(PyObject) more) and offseted the
    Self pointer to start after the PyObject header (containing the space reserved for the ob_refcnt and ob_type fields). So, when the ob_refcnt and ob_type properties
    access their associated data, they pick it from this extra hidden header.
    Note that when using GetSelf, it will return a pointer to the the start of this hidden header. And the Adjust method will correct Self to move after this header.
    Finally, in FreeInstance, we free the memory only if PythonAlloc is False.

    A   B C

    PyObject header


    TPyObject class

    4 bytes
    4 bytes
      hidden Class Ptr
    4 bytes
    4 bytes
    1 byte
    1 byte
    A = ptr returned ptr returned by Adjust   B = ptr returned by Adjust  


    • a Python object must start at A.
    • a Delphi class class must start at B
    • TPyObject.InstanceSize will return C-B
    • Sizeof(TPyObject) will return B-A
    • The total memory allocated for a TPyObject instance will be C-A, even if its InstanceSize is C-B.
    • When turning a Python object pointer into a Delphi instance pointer, PythonToDelphi will offset the pointer from A to B.
    • When turning a Delphi instance into a Python object pointer, GetSelf will offset Self from B to A.
    • Properties ob_refcnt and ob_type will call GetSelf to access their data.

      Subclassing TPyObject in Delphi (TPyPoint = class(TPyObject))
    A   B C E

    PyObject header


    TPyObject class

    TPyPoint class

    4 bytes
    4 bytes
      hidden Class Ptr
    4 bytes
    4 bytes
    1 byte
    1 byte
    4 bytes
    4 bytes
    • TPyPoint.InstanceSize will return D-B
    • The total memory allocated for a TPyPoint instance will be D-A
    • The Python type object will have D-A in its tp_basicsize slot.
      in RegisterMembers, calling PythonType.AddMember('x', mtInt, Integer(@TPyPoint(nil).x), mfDefault, 'x coordinate');
      will produce an offset of C-A, instead of C-B, because AddMember will add automatically B-A to the offset.

      Subclassing TPyPoint in Python (class MyPoint(spam.Point))
    A   B C D E

    PyObject header


    TPyObject class

    TPyPoint class


    4 bytes
    4 bytes
      hidden Class Ptr
    4 bytes
    4 bytes
    1 byte
    1 byte
    4 bytes
    4 bytes
    4 bytes
    • The total memory allocated for a MyPoint instance will be E-A
    • The Python type object will have E-A in its tp_basicsize slot.
    • The Python type object will have D-A in its tp_dictoffset slot (it is the tp_basicsize of the inherited type, accessible through tp_base).
    • The memory allocation is done by Python, that also initializes parts A-B and D-E, leaving us an available space between B and D. That's why we can't have the
      ob_refcnt and ob_type fields inside the TPyObject class definition, as they would appear in the free space available for the parent types and would not be used by Python. This would not be an issue, except for calculating the exact member offsets.

    So, hiding the PyObject header and ensuring this always comes first, makes it consistent
    in all cases for the member offsets to remain valid.
  • Added Demo26 to show how you can build base types (This is an adaptation of Demo8), and updated Tutorial.txt for giving some explanations to the new way of building types allowing subclassing.
  • Allowed a TPythonType to be dynamically created after everything has already been setup. It means that the module hosting the type will effectively have a variable
    referencing the new Type object and a CreateXXX function for creating new instances of that type.

Version 3.24 (Jan 29, 2003)
  • Fixed nasty bug that would freeze Kylix2 IDE (and maybe Delphi6/7 in some cases):
    in unit PythonGUIInputOutput.pas, method TPythonGUIInputOutput.Notification did not call inherited!
  • Fixed bug in PythonEngine.pas, in VariantAsPyObject when called by VarPyth.TPythonVariantType.VarDataToPythonObject.
    It caused a variant memory error when doing a dict.SetValue('key', ''); (empty string).
    Bug reported by Andy Bulka [abulka@netspace.net.au]
  • Added Python 2.3 compatibility:
    - new bool type: PyBool_Check, PyBool_FromLong
    - new date, time, datetime, delta... types from new datetime module
    - new property DatetimeConversionMode in TPythonEngine allowing to decide how a variant containing a datetime should be converted into a Python object.
    Presently there are only 2 modes: the default is dcmToTuple (a tuple containing year, month, day...) and starting with Python2.3 you get dcmToDatetime that will use the new datetime objects of the datetime module. I could not set it as default to avoid breaking existing code.
    - new exceptions: PyExc_FutureWarning, PyExc_PendingDeprecationWarning, PyExc_UnicodeDecodeError, PyExc_UnicodeEncodeError, PyExc_UnicodeTranslateError

    - new APIs (note that some of them were missing since previous Python versions):
    PyType_IsSubtype, PyObject_TypeCheck, PyBaseString_Check
    PyObject_GC_Malloc, PyObject_GC_New, PyObject_GC_NewVar, PyObject_GC_Resize,
    PyObject_GC_Del, PyObject_GC_Track, PyObject_GC_UnTrack
    PyType_IS_GC, PyObject_IS_GC
    PySlice_GetIndicesEx, PySlice_Check
    PyString_DecodeEscape, PyString_Repr

    - new behaviour:

    With Python2.3 the following functions return True if the Python object is the expected type or
    one of its descendants:

    To check if a Python object is really (and only) the expected type then use the new functions instead:
  • in unit VarPyth.pas, added functions:

  • updated Demo25 to reflect last additions made to VarPyth.pas