ctypes and addressof

Here’s a gotcha I came across in ctypes a while ago. Have a look at the code below, and see if you can work out what it will print:

import ctypes

int_array_type = ctypes.c_int * 2
pint_array_type = ctypes.POINTER(ctypes.c_int)


def display_values(pointer_list):
    #print("pointer_list = %s" % pointer_list)
    for i in range(3):
        pint_array = ctypes.cast(pointer_list[i], pint_array_type)

        print("values of pointer_list[%d] are [%d, %d]" % (i, pint_array[0], pint_array[1]) )


def wrong():
    pointer_list = []
    for i in range(3):
        int_array = int_array_type()
        for j in range(2):
            int_array[j] = i + j

        pointer_list.append(ctypes.addressof(int_array))

    display_values(pointer_list)


wrong()

If you’re using Python 2.x or Python 3.x, then you might be surprised. Your values may vary, but I get:

values of pointer_list[0] are [2, 3]
values of pointer_list[1] are [11187064, 0]
values of pointer_list[2] are [2, 3]

(If you’re using IronPython 2.6.1, the code works, and does not display this particular problem).

Uncommenting line 7 gives us a bit more of a clue. Your values will vary, but mine produces:
pointer_list = [11187064, 11187144, 11187064]

It took me ages to work out what was going on here. The problem seems to be that storing the address of some Python variable (in this case int_array) is not enough to keep it from being reused. The addressof method returns an integer, and this is not a Python reference, so the memory can be reused. And ctypes seems to reuse it every other time.

So one way round this problem would be to keep a reference to it in some other way. There are many ways to do this, but one example would be:

import ctypes

int_array_type = ctypes.c_int * 2
pint_array_type = ctypes.POINTER(ctypes.c_int)


def display_values(pointer_list):
    #print("pointer_list = %s" % pointer_list)
    for i in range(3):
        pint_array = ctypes.cast(pointer_list[i], pint_array_type)

        print("values of pointer_list[%d] are [%d, %d]" % (i, pint_array[0], pint_array[1]) )


def right():
    pointer_list = []
    safe_store = []
    for i in range(3):
        int_array = int_array_type()
        for j in range(2):
            int_array[j] = i + j

        pointer_list.append(ctypes.addressof(int_array))
        safe_store.append(int_array)

    display_values(pointer_list)


right()

This produces the correct output:
values of pointer_list[0] are [0, 1]
values of pointer_list[1] are [1, 2]
values of pointer_list[2] are [2, 3]

Posted in Python, Software | Tagged , | Leave a comment

Python decorators

I have been learning about decorators recently. It is interesting functionality, but also one of those areas where the issues just keep appearing, the more you look at it.

There are some good articles on it here and here

To my mind, a key requirement of decorators, after the need to be useful, is to be as unintrusive as possible. So the decorated function or method, and more particularly, users of the decorated function or method should not notice the decoration.

Some of the issues, in order of increasing complexity:

  • functions and methods
  • return values
  • function / method arguments and keyword arguments
  • attributes such as __name__ and __doc__
  • decorator arguments
  • multiple decorators
  • introspection

I don’t have all the answers yet, and I’ll write more in a later post.

An example implementation shows some of the points of interest. This is a decorator with arguments implemented using a function.

from functools import wraps

def decoratorWithArguments(decoratorArgument = None):
    def wrap(functionOrMethod):
        # Support naive introspection
        @wraps(functionOrMethod)
        def wrappedFunctionOrMethod(*args, **kwargs):
            print("Before %s" % str(decoratorArgument) )
            ret = functionOrMethod(*args, **kwargs)
            print("After %s" % str(decoratorArgument) )
            return ret

        return wrappedFunctionOrMethod
    return wrap


@decoratorWithArguments("Decorator Argument Value")
def functionExample():
    """ functionExample docstring """
    return "functionExample"


class ClassExample:
    @decoratorWithArguments()  # defaults to None
    def methodExample(self):
        """ methodExample docstring """
        return "methodExample"


print(functionExample())
classInstance = ClassExample()
print(classInstance.methodExample())

Notes:

  • the wraps function from functools copies across various attributes such as the docstring.
  • *args and **kwargs should cope with both positional arguments and keyword arguments
  • Because decorators work differently with and without arguments, even though this decorator will work without any arguments, I still need to use () on line 22.

It took me an age to understand how decoratorWithArguments could possibly work. It’s a bit like Russian dolls:

  • The outer function, decoratorWithArguments, takes the decorator arguments. It returns the inner function, wrap (a closure).
  • Having unwrapped the outer function, we now have the returned inner function (wrap). This can then be called with the function or method that we want to decorate. It returns the inner function, wrappedFunctionOrMethod.
  • wrappedFunctionOrMethod can then be called. It will be called in place of the original decorated function or method.

Note that the decoration process takes care of all of the above for us. It’s still nice to understand how it can work.

Posted in Python, Software | Tagged | Leave a comment

Ubuntu upgrade

I wanted to install an Ubuntu upgrade on a very old machine, from 8.04 LTS (Hardy Heron) to 10.04 LTS (Lucid Lynx). I like Ubuntu, so please do not take this post as a moan about it.

(See here for more information on Ubuntu releases.)

The download of the packages went fine, but the upgrade froze at about 75%. Which is probably not a good thing, as there is no cancel option at this point. Sure enough, on the reboot, the system was not happy.

It was at this point that I discovered the CD-player on the computer was not working either (a hardware issue rather than anything to do with the upgrade).

Luckily, I had an old copy of 6.06 LTS (Dapper Drake) that I could use to back up important data.

I then looked around for non-CD installation options. There seemed to be 3 options:

  • Install from ISO mounted on a partition
  • Install from ISO placed on a drive
  • Install from the network

This is not an area that I am overly familiar with, so problems that I had are likely to be PEBKAC.

The method that I eventually got working is the install from the network. Here are a few hints:

  • The install can appear to hang in places. This usually means that it is taking a long time. I got quicker response times later in the evening
  • It offers the option of installing lots of extra software towards the end. Don’t! Because your system will not be left in a working state if anything goes wrong at this point. Just install the necessary software later on, once you have a working system. The install process is much more robust once Ubuntu is installed.
  • Take care to get the right linux and initrd.gz files. These exist, for each Ubuntu version, for a reboot from the network, an install from the network, and many other purposes.

I also learned a lot about fdisk and the GRUB (bootloader). GRUB is a very useable piece of software. I will write more about it in a later post.

I managed to get Lucid Lynx installed, but it is too slow on the machine (256MB of memory, so maybe not too surprising). Hardy Heron continues to be my default version, and is pleasantly responsive.

Posted in Software | Tagged | Leave a comment

Python whitespace

I was asked in an interview yesterday what I think of Python white space.

Python is unusual (possibly unique?), in that the indentation of your code is significant, and effects the way that your code is compiled / runs.

I know that when I first used Python, I was ambivalent about this feature.  But as a seasoned user of Python, I think it is a good feature.

Firstly, the way we lay out code is often designed to make it more readable for humans.  But if the way the code runs ignores this layout, then there is a danger that bugs will be introduced through this disconnect.

Secondly, the fact that whitespace is significant allows Python to eliminate braces (or other code grouping statements): so you avoid all the coding standards “discussions” on the correct style of braces, which can occupy huge amounts of (unproductive) time, and adversely impact team morale before you have even started.

Here’s an example in C:

#include <stdio.h>

int main(void)
{
    int a = 1;
    int b = 2;

    if (a == 1) {
        printf("a is 1\n");
    }

    if (a==1)
    {
        printf("a is 1 still\n");
    }
    if (a==1)
        {
        printf("a is 1 yet again\n");
        }

    if (a==1 && b==3)
        printf("a is 1 for the last time\n");
        printf("b is 3\n");
}

All three of the bracing styles that I have encountered are displayed here (I won’t inflame the discussion by stating my preference, only to say that the example above is inconsistent in its use of braces, and that is not desirable. The final section is potentially misleading to a developer, although the compiler will not complain.

The common point of all three of the styles of braces is that the code within the braces is indented. Which the Python approach follows as well. Here is the equivalent Python example:

a = 1
b = 2

if a == 1:
    print("a is 1")

if a==1:
    print("a is 1 still")

if a==1:
    print("a is 1 yet again")

if a==1 and b==3:
    print("a is 1 for the last time")
print("b is 3")

Note that, because whitespace is significant, it is essential that everyone on the team ensures that tabs are converted to spaces, or their tab indent is set to the same value. In my experience, the former is preferable.

Posted in Python, Software | Tagged | Leave a comment

Python 32/64

As a newbie to Windows 7, I am just enjoying (sic) the introduction to 64-bit software, and the interaction with the legacy 32-bit software.  Luckily, I have just one 16-bit application (nothing to do with Python), which will no longer run.

I am glad to say that Python has had 64-bit versions starting with 2.6, and it seems to cope well with having both 32 and 64-bit versions installed alongside each other.

Aside: Many developers are keen to write code that runs on multiple operating systems.  I like to do the same for multiple Python versions, so I have a lot of them installed, for testing purposes.

In particular, the installer creation in distutils (usually interfaced via setup.py) is able to create 32 and 64-bit installers (depending on the version of Python that it is run with), and the installers provide a sensible list of installed Python versions.  So a 32-bit installer provides a list (and correct locations) of 32-bit Python installs, the 64-bit installer provides a list of 64-bit Python installs.

It’s always good when software works straight out the box, and works sensibly! (Yes, I know it means that someone else has put the effort in upstream – much appreciated).

Posted in Python, Software | Tagged | Leave a comment

Open-Source

I am constantly amazed by how much great software there is available for free.  As an introduction, here are some that I use on a regular basis:

  • Apache web server 2.2
  • GCC 3.4.5
  • Java 1.6.0_18
  • MinGW / MSYS
  • Mozilla Firefox 3.5.8
  • OpenOffice 3.2.0
  • Python 2.5, 2.6, 3.0 and 3.1
  • SciTE 2.01

I also use Opera 10.53, which is free but not open-source, and Windows XP / 7 the majority of the time – not free or open-source.  However, I prefer to write code that works across platforms as far as is possible.

Posted in Python, Software | Tagged | Leave a comment