Namespaces in Python – Revisited

Taking a short break from my artwork craze (but I promise more is to come), I reviewed some of the new features and changes in Python, brought by versions 2.6 and 3.0. There are many interesting features, but a very specific one caught my eye: the ability to modify existing properties.

From the documentation:

Properties now have three attributes, getter, setter and deleter, that are decorators providing useful shortcuts for adding a getter, setter or deleter function to an existing property. You would use them like this:

class C(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

class D(C):
    @C.x.getter
    def x(self):
        return self._x * 2

    @x.setter
    def x(self, value):
        self._x = value / 2

I found this very interesting. If you're, for some reason, a frequent reader of this blog, you'd remember how in a previous post I suggested a hack to allow namespaces inside Python classes. However, it was largely incomplete because I couldn't get it to work for properties. Perhaps now I can?

Now, don't let that pretty decorator syntax mislead you. Doing:

    @x.setter
    def x(self, value):
        self._x = value

is exactly identical to doing:

    def x_set(self, value): # Name changed to preserve 'x'
        self._x = value
    x = x.setter(x_set)

And this is exactly what I was missing to complete my code.

So here is the new make_namespace, applying also to properties:

(This was only tested on Python 3, but should also work for Python 2.6. It will not work on version 2.5 or lower)

import types
def make_namespace(self, ns_cls):  
    "This code iterates all functions and properties in ns_cls and binds them to self"
    for attr_name in dir(ns_cls):  
        attr = getattr(ns_cls, attr_name)  
        if type(attr) == types.FunctionType:
            setattr(ns_cls, attr_name, attr.__get__(self) ) 
        elif type(attr) ==  property:
            setattr( ns_cls, attr_name, attr
                    .getter( lambda x  : attr.fget(self))
                    .setter( lambda x,v: attr.fset(self,v))
                    .deleter(lambda x  : attr.fdel(self))
                )
    return ns_cls()

Notice that I can chain getter, setter, and deleter, because they all return a property object.

And here is a possible usage:

class YetAnotherGuiWindow:
    def __init__(self, pos, size, ...):
        ...
        self._size = size
        self.spatial = make_namespace(self, self.spatial)

    class spatial:
        ...
        def _get_size(self):
            return self._size
        def _set_size(self, size):
            self._size = size
        size = property(_get_size, _set_size)
        ...

...
# Meanwhile, in my console
>>> g.spatial.size = (100,100)
>>> g.spatial.size
(100, 100)
>>> g.spatial.size = (140,10)
>>> g.spatial.size
(140, 10)
>>> g._size
(140, 10)

I hope you'll find this useful!

Tags: , , , , ,

Categorised in:

Leave a Reply

Your email address will not be published. Required fields are marked *