Anonymous objects in Python

In C, it is possible to create structures which have no explicit type.

struct{
    int x;
    int y;
}aPoint;

In this example aPoint is an instance of a struct. It has members x and y. There is no explicit type associated with aPoint. Of course, the compiler generates a type, but you can't instantiate anymore objects of this type. There are legitmate reasons for using an anonymous structure. Consider the following

struct{
    char * mem;
    int length;
    int size;
}buffer;

This example creates an instance named buffer. In this example you could malloc some memory and store the pointer in buffer.mem, store the total size of the memory segment in bytes in buffer.size, and store the number of bytes currently used in buffer.length.

Python

There is no direct equivalent to anonymous structures in Python 2.x. You can of course define a complete class and create only one instance of it. It turns out you can emulate the behavior pretty easily however. The type function is a builtin. It can be called with either 1 or 3 arguments. To create anonymous objects, it is called with 3 arguments. Consider this example

anon = type('',(object,),{})()

The first argument is the name of the type, we can pass the empty string since the intent is to create anonymous object. The second argument is a tuple of all of the bases classes of this object. In this example only object is passed but multiple bases could be specified. The third parameter is a dictionary of definitions for the class body. After the call to type is closed the () calls the returned value from type. This results in a new object being instantiated which is assigned to anon. At this point the type is anonymous. Unlike C, you can just use the single argument version to retrieve the type. Calling type(anon) returns the original type object allowing you to instantiate further instances if you cared to.

As you can probably see, the object in the above definition is pretty much useless. Heres an object that is potentially useful.

obj = type('',(object,),{'a':5,'b':6,'c':7})()

I've not really found a case where this idiom is appropriate, but it is still interesting. Functions can be added through two methods

def _getA(self):
    return self.a

obj = type('',(object,),{'a':5,'b':6,'c':7,'getA':_getA,'getB':lambda self : self.b})()

What is really interesting is you can create nonsense objects such as

obj = type('',(object,),{1:'foo'})()

This actually creates an object with an attribute of 1. If you use dir(obj) it shows up plainly

>>> dir(obj)
[1, '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

But you can't do obj.1 as that is not even syntactically valid. You can't use getattr either because it expects a string for the attribute name to retrieve.

Obviously, the type builtin was not intended for everyday use. With great power comes the ability to cause all sorts of future nightmares.


© Eric Urban 2013