Python Programming, news on the Voidspace Python Projects and all things techie.

CarbonPython - a Faster Python for .NET

emoticon:globesearch This is very exciting, a new development from Antonio Cuni the author of the .NET backend for PyPy:

CarbonPython is an RPython compiler for PyPy that can produce .NET assemblies. These assemblies can be used directly from C# and IronPython.

So why would you want to use this over IronPython? Well, RPython is a restricted subset of Python that can be statically compiled. So CarbonPython produces code that runs faster than IronPython, much faster. Antonio claims that compiled RPython can run as fast as C# (and 250 times faster than IronPython), and the benchmarks from the CLI backend basically justify these claims.

This means that IronPython applications in particular can move speed critical sections of code into RPython rather than into C#. great news

Another advantage is that classes compiled with CarbonPython can be consumed by C#, which is not the case with classes defined in IronPython.

This is still pre-alpha and there are limitations: you can't reference assemblies outside mscorlib, the API for accessing .NET classes is still being worked on, and you can't use .NET indexers or properties directly yet (to name a few).

This is great news though, and did I say that it was very exciting?

Best of all though is the name - can you guess why it is called CarbonPython? Yup, CarbonPython combined with IronPython produces the even tougher SteelPython... Cool

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-06-28 22:51:50 | |

Categories: ,


Descriptors and Attribute Lookup Order

emoticon:exclaim over the last few months I've gradually been sidling up to a better understanding of the descriptor protocol. Descriptors are how things like properties are implemented, and affect attribute lookup through the mysterious __getattribute__ method.

Descriptors mean that if an object being looked up as an attribute has __get__, __set__ or __delete__ defined, they will be called to fetch (or set or delete) the attribute. They are different from __getattr__, __setattr__ and __delattr__ in that the descriptor protocol is used for normal attribute access. In particular, __getattr__ is only invoked if the attribute isn't found the 'usual' way.

I was blocked on understanding the descriptor protocol before by the following line in the 'How-To Guide':

If an instance's dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence.

The missing piece of the jigsaw was how attributes are looked up, specifically the order they are looked up. I knew that if an instance has an attribute, then that takes precedence over a class attribute. So how could a 'data-descriptor' ever take precedence? Surely if Python finds an instance attribute it stops looking?

In fact (and as the guide explains...) this isn't how attributes are looked up. When you lookup an attribute on an instance (for example some_object.attribute), Python first looks on the class. If it isn't found it looks on the base class, and all the way up using the mro to search all the base classes. Finally it looks on the instance, by checking inside its __dict__.

If the object is found on the instance and on the class, then usually the instance attribute takes precedence. However, if the class attribute is a data-descriptor (an object that has both __get__ and __set__), then the class attribute will be used instead of the instance attribute.

What this means, is that if you have an object with a property, even if you poke an attribute with the same name into an instance dictionary, the property will be invoked instead:

>>> class AnObject(object):
...     @property
...     def attribute(self):
...         print 'Property fetched'
...         return 'got'
...
>>> something = AnObject()
>>> something.attribute
Property fetched
'got'
>>> something.__dict__['attribute'] = 'not got'
>>> something.attribute
Property fetched
'got'
>>>
>>> something.__dict__['attribute']
'not got'
>>>

Smile

One result of this though, is that even a simple attribute access means looking on the class and all the base classes of the object before the instance attribute will be returned. Use locals where possible!

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-06-23 16:20:18 | |

Categories: ,


Gnuplot: Success at Last!

emoticon:pda I've finally got to grips with Gnuplot. I can now provide with a set of points representing x, y, z co-ordinates (a height map) and have it draw the appropriate surface - with contours. phew

I learned a phew things along the way:

  • When you specify paths in a gnuplot script, you must use '/' as the directory separator (even on good old Windoze) #!$*&$
  • When you launch subprocesses with IronPython, you need to put quotes round the path to the gnuplot script (the arguments)!
  • Interactive mode is useful for experimenting.
  • You must set the GNUPLOT_FONTPATH environment variable (and possibly GDFONTPATH - I always set both)

The (a?) data format that the splot command likes is:

x0 y0 z(0, 0)
x1 y0 z(1, 0)
x2 y0 z(2, 0)
...
xN y0 z(N, 0)

x0 y1 z(0, 1)
x1 y1 z(1, 1)
x2 y1 z(2, 1)
...
xN y1 z(N, 1)

...

x0 yN z(0, N)
x1 yN z(1, N)
x2 yN z(2, N)
...
xN yN z(N, N)

This is each coordinate (x, y, z) on a separate line, with every 'row' (new y coordinate) separated with an extra newline.

A 3D surface generated from gnuplot

The following Python script generates a data set of x, y, z coordinates from the formula z = sin(x*x + y*y) / (x*x + y*y). It saves a gnuplot script and launches gnuplot to generate the image.

import os
from math import sin
from System.IO import Path
from System.Diagnostics import Process


def CreateScript(template, scriptPath, data, imagePath):
    h = open(scriptPath, 'w')
    h.write(template % (imagePath.replace('\\', '/'), data))
    h.close()


def LaunchGnuplot(gnuplotPath, scriptPath, fontPath):
    proc = Process()
    proc.StartInfo.FileName = gnuplotPath
    proc.StartInfo.Arguments = '"%s"' % scriptPath
    proc.StartInfo.EnvironmentVariables['GDFONTPATH'] = fontPath
    proc.StartInfo.EnvironmentVariables['GNUPLOT_FONTPATH'] = fontPath
    proc.StartInfo.UseShellExecute = False
    proc.Start()
    proc.WaitForExit()


# You might need to change this for Windows 2000 and Windows NT systems
fontPath = r'c:\Windows\Fonts'

# Various paths needed by the scripts
gnuplotPath = os.path.abspath('gnuplot\\wgnuplot.exe')
scriptPath = os.path.abspath('create_surface.gp')
imagePath = os.path.abspath('image.png')


# The template for the gnuplot script
# Experiment with this!
template = r"""
set terminal png nocrop enhanced font verdana 12 size 640,480
set title "Gnuplot Demo"
set xlabel "X axis"
set xlabel  offset character -2, -2, 0
set ylabel "Y axis"
set ylabel  offset character 2, -2, 0
set zlabel "Z axis"
set zlabel  offset character 1, 0, 0
set output '%s'
set contour both
set view 45, 30
set style data lines
set hidden3d
splot "-" title "The Data"

    %s

"""


out = []
# Generate the data
for y in range(1, 50):
    v = (6.0 / 50) * y - 3
    row = []
    for x in range(1, 50):
        u = (6.0 / 50) * x - 3
        try:
            value = sin(u*u + v*v) / (u*u + v*v)
        except ZeroDivisionError:
            # for the point where u and v are both 0
            value = 1
        row.append('%s %s %s' % (u, v, value))
    out.append(row)

data = '\n\n    '.join('\n    '.join(row) for row in out)

CreateScript(template, scriptPath, data, imagePath)
LaunchGnuplot(gnuplotPath, scriptPath, fontPath)

(You can download it here. You will need the gnuplot binary of course.) I'm afraid it is for IronPython, but is should be simple enough to translate it for CPython using the subprocess module.

Let me quickly take you through the gnuplot commands it uses (in the template variable):

  • set terminal png nocrop enhanced font verdana 12 size 640,480

    This tells gnuplot that we want a '.png' file as the output. Text is to be produced using the Verdana font, and the image size will be 640x480 pixels.

  • set title "Gnuplot Demo"

    Set the title on the image.

  • Set the axis labels and the label locations:

    set xlabel "X axis"
    set xlabel  offset character -2, -2, 0
    set ylabel "Y axis"
    set ylabel  offset character 2, -2, 0
    set zlabel "Z axis"
    set zlabel  offset character 1, 0, 0
    
  • set output '%s'

    This sets the filename (and path) for the output image. The '%s' is replaced with the real path of course.

  • set contour both

    This tells gnuplot to draw contour lines on both the surface and on the base of the image. Alternative options are set contour surface and set contour base. You can also remove this line to get rid of the contour lines.

  • set view 45, 30

    This is the angle that the view will be produced from. The format is set view <rot_x>, <rot_z>. See the view command documentation for full details. Another interesting option is set view map.

  • set style data lines

    Tell gnuplot to turn our data points into lines.

  • set hidden3d

    Tell gnuplot to do hidden line removal.

  • splot "-" title "The Data"

    splot is the command for drawing 3D plots. The "-" tells gnuplot that we are embedding the data in the script (it will replace the '%s'). The 'title' is actually for the data line rather than for the whole image.

Hopefully this will be of useful for someone trying to draw charts or graphs on Windows with gnuplot. I think this really is the last entry on charting for a while...

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-06-23 15:40:07 | |

Categories: , ,


Hosted by Webfaction

Counter...