devork

E pur si muove

Singletons in a Python extension module

Tuesday, June 23, 2009

If you want a singleton in a C extension module for CPython you basically have to do the same as when doing this in plain Python: the .__new__() method needs to return the same object each time it is called. Implementing this has a few catches though.

static PyObject *
MyType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    static MyObject *self = NULL;

    if (self == NULL)
        self = (MyObject *)type->tp_alloc(type, 0);
    Py_XINCREF(self);
    return (PyObject *)self;
}

Then assign this function to the tp_new slot in the type. There's two things of interest in this function:

  • self is declared as static. Normally this would not be the case, but declaring it as static makes it stay alive after the function has returned and it will still be pointing to the first instance of our object, so the next time a new object is asked for this is simply returned.
  • Before returning the pointer to the static self, the reference count is increased. This may seem odd but is the right thing to do, otherwise the reference count will not go up for subsequent calls to the new function since the reference count is increased by PyType_GenericAlloc() (via the call from the pointer in the tp_alloc slot). So if you don't do this you end up with negative reference counts, which doesn't make python very happy. This does mean you never end up deallocating the object since the lowest reference count you have is 1, but you wanted a singleton right?. If you really wanted to get the reference count to drop to 0 then you can always put the Py_INCREF() in an else clause.

Voting and identification in the UK

Sunday, June 07, 2009

Last Thursday I had the pleasure of being able to vote for the local council as well as for the European Parliament. Since I'm a Belgian citizen living in the United Kingdom this involved convincing the officials at the voting office to re-read their instructions (at first they only allowed me to vote for the local council but not for Europe, I think they must have realised how silly that sounded) but otherwise was quite easy. Too easy.

When I went to the polling station I forgot my poll card, but my colleagues at work said that would be fine (not that going home to pick it up was very far) so I tried it anyway. No problem, the only thing they asked is where I lived, then found my name on their list and let me vote (after above-mentioned debacle). There was absolutely no verification that I was who I claimed to be. Seriously, it is rather trivial to vote for someone else, I'm sure you can visit 2 or 3 polling stations and vote in someone else their name. Just talk to friends and work a little bit together and you can all cast half a dozen votes if you're a little careful. And they have no way of recovering from this, other then having to let everyone using that voting station re-cast their vote.

After some talking to people they seemed to think that there is no single means of identifying someone in an official way in the UK. This means that buying alcohol is better controlled then voting, since there you either have a form of ID (if you look under 21) or you don't get to buy it. But for voting? No ID required, because there is none.

I'm sure the ID card scheme as currently proposed in the UK is not any good, but there does appear to be a problem that might have to be fixed somehow. By now I'm pretty sure that if you give me 2 years I can create a fictitious John Smith person, he'll have a passport, driving license, voting rights, bank account and be native British. Seriously, it's easy. You just need some time.

Raising exceptions in threads

Saturday, June 06, 2009

It's not simply raising an exception in a thread that I want. I want to raise an exception in a thread from another thread. It's like sending signals to threads, only signals in pyhon can only be delivered to the main thread (for portability). But Python has a other asynchronous signaling system: exceptions.

I'd like to be able to do something like:

for t in threading.enumerate():
    thread.raise(MyAppDoesntWantYouAnymoreError)

Is this possible? Are there other ways to do this sort of thing?

Alternatively I might be happy with a fix for issue1856, but I do think it might be nice to be able to signal threads in an asynchronous way in any case.

Subscribe to: Posts (Atom)