A Ticking TimeBomb

Generally speaking, you can only raise exceptions when your code is being called. Wouldn't it be nice if instead you could leave a time bomb that would go off later?

class TimeBomb(object):
    def __del__(self):
        raise Exeption("BOOM!")
>>> t = TimeBomb()
>>> t = 3
Exception Exception: Exception('BOMOM!',) in <bound method TimeBomb.__del__ of <__main__.TimeBomb object at 0x0122E090>> ignored

When the Python garbage collector sees the TimeBomb instance, it does its business, first calling __del__ and then freeing the memory. Notice that while the Exception is raised and printed, it's also ignored by design.

Reference count yourself lucky this day.


ctypes: The keys to the kingdom

Like it or not, most of the code in the world is not written in Python.

It's probably for the best, because one can only imagine how much maintaining some mid-90s, Python 1.4 library would suck today. But seriously, there are a lot of languages and libraries out there, and Python's OK with that.

Take the ssl module. OpenSSL is a powerful, open-source standard when it comes to libraries, but the ssl module only became a first-class core library in Python 2.6. And even then, OpenSSL has a lot of power to offer beyond what's exposed in the module. How do we get at that one obscure function?1

Enter ctypes, Python's convenient and powerful portal to the C FFI. Given the prevalence and power of C, ctypes gives you access to everything from scientific libraries to the low-level guts of your OS. In our OpenSSL example, that might look like this:

>>> import ctypes
>>> libssl = ctypes.cdll.LoadLibrary('libssl.so')
>>> libssl.PEM_read_bio_PrivateKey
<_FuncPtr object at 0x24bb530>

Now you have an SSL function, not provided by the standard ssl module, but still ready to be called from Python.

In a simplistic way, Python is to C as C is to assembly, both in concept and implementation. C lets you embed assembly, and Python gives you an interface to C. Of course, just as too much assembly in C is probably a bad code smell, for involved use cases, you'll probably want to look at Cython and Weave.

[1]Historical note: before ctypes, one could wrap the library as a Python module, but this meant building against a specific version of Python, among other headaches. That said, the practice still has its place.

reload() does not regenerate existing module objects

The reload() function is one of the most legitimately unintuitive built-in functions in Python. On the surface it fulfills a simple and fundamental role: reloading a module as though it was being imported for the first time, presumably because it has changed or needs some state reset.

Unfortunately, doing this in a comprehensive fashion is actually very involved, and the reload() function understandably doesn't even really try. Here's an basic example of how it might violate one's expectations:

>>> import json  # arbitrary example module
>>> oldjson = json
>>> reload(json)
<module 'json' from '/usr/lib/python2.7/json/__init__.pyc'>
>>> json is oldjson
True

As you can see, the json module is successfully reloaded, but the original object remains in memory. Furthermore, any attributes added to that namespace also stick around:

>>> json.a = 'A persistent attribute.'
>>> reload(json)
<module 'json' from '/usr/lib/python2.7/json/__init__.pyc'>
>>> json.a
'A persistent attribute.'

As mentioned before, cleaning up modules in memory is a tricky process. If someone wants to submit a patch, we'd be much obliged for the life sacrifice. :)


Making ``dict(myobject)`` do something useful

Normally if you pass your run-of-the-mill object to the dict() constructor, you'll see an error. If only there were a sane and succinct default...

class A(object):
    def __iter__(self):
        return self.__dict__.items().__iter__()

This example class is now iterable and returns an iterator over its instance members/values.

>>> a = A()
>>> a.knight = "ni"
>>> a.peon   = "newt"
>>> dict(a)
{'knight': 'ni', 'peon': 'newt'}

Note again that this only covers instance-level members and doesn't include anything from the class or inheritance structure. See PDW 8 for a note on that sort of thing.


Every string is an iterable of strings

In case you hadn't noticed, strings aren't your average iterable.

>>> 'a'[0][0][0][0][0]
'a'

Good news is, Python doesn't actually create a bunch of string objects when you do this.

>>> a = 'a'
>>> id(a) == id(a[0][0][0][0])
True

Phew! Dodged a bullet there.