Attributes with special behaviour in Python
If you are using python 2, your code doesn't work at all. I'll assume you are using python 3.

There a few cases where this will do unexpected things:

t=Test(set())
t.a.add(2)
print t.a


The set will empty.

b = set()
t = Test(b)
b.add(2)
print t.a


The set will again be empty.

These issues are caused because set are mutable. They go away if you only use immutable objects, such as frozenset(), or if you just never use the mutable operations on the sets.


  I was wondering if I can avoid the hidden attribute _a


Instead of providing the name as a parameter, have DefaultAttr make one up such as '_' + str(id(self)). That'll provide a unique attribute to store data on.


  Also the "Void" solution seems dodgy


Instead of "Void" use object(). It'll avoid a string comparison and be guaranteed unique.

Alternately, delete the attribute using delattr instead of storing anything there. Absence of the attribute indicates that you should use the default value.

Alternately, if you restrict the use of the object to immutable objects, just store a reference to the immutable object there. There is no need to use a special sentinel value. Here is my code to implement that idea:

class DefaultAttr(object):
    def __init__(self, empty):
        self._empty = empty
        self._name = '_' + str(id(self))

    def __get__(self, obj, owner=None):
        return getattr(obj, self._name)

    def __set__(self, obj, value):
        if value == self._empty:
            value = self._empty
        setattr(obj, self._name, value)



  The background is that my program had sparse data, meaning that there
  were a lot of objects having empty sets in their attributes which
  wasted a lot of memory.


Actually, your probably shouldn't be doing this at all. Instead, use frozenset(). Whenever you call frozenset() it returns the same set, so the empty sets won't take up excess memory. If you rework your app to use them, you should use much less memory.