Anonymous objects in Python
- Monday September 23 2013
- python object-oriented c
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.