I would like to dynamically bind descriptors to attribute of a class.
For example I have this descriptor (it is just a dummy example):
class Item(object):
def __init__(self, filename):
self.filename = filename
def __get__(self, obj=None, objtype=None):
#print '__get__(%s, %s)' % (obj, objtype)
return open(self.filename).read()
def __set__(self, obj, val):
#print '__set__(%s, %s)' % (obj, val)
open(self.filename, 'w').write(str(val))
In my main container, I would like to dynamically register my descriptors.
Everything works great if I instanciate the descriptors at the class level:
class Container(object):
foo = Item('foo')
bar = Item('bar')
Unfortunately when I try to associate the descriptor dynamically using setattr
I need to put a lot more complexity to my class:
class Container(object):
def __init__(self, data):
for attr in data:
super(Container, self).__setattr__(attr, Item(attr))
def __setattr__(self, name, value):
#print '__setattr__(%s, %s)' % (name, value)
attr = super(Container, self).__getattribute__(name)
if hasattr(attr, '__set__'):
attr.__set__(name, value)
else:
super(Container, self).__setattr__(name, value)
def __getattribute__(self, name):
#print '__getattribute__(%s)' % (name)
attr = super(Container, self).__getattribute__(name)
if hasattr(attr, '__get__'):
return attr.__get__(name)
return attr
The expected output is:
>>> c = Container(['foo', 'bar'])
>>> c.foo = 2
>>> c.foo
'2'
Is there a simpler solution with less kludges?
So, you're almost there with your __init__
in container. The problems you have:
super(...).__setattr__
makes no sense, tbh. There's setattr for thisTricky part with descriptors (btw, from my experience, it's kind of "default" obstruction when people start using them). When you use descriptors in non-dynamic way with
class Container(object):
foo = Item('foo')
bar = Item('bar')
you are setting foo
and bar
in scope of the class - literally as class attributes. But in your "dynamic" way you're doing it with instance. Idk if you tried to set it as class, but if this was an intention, super
doesn't work like this. To set attach descriptor dynamically, you need to attach it to class of your instance (referred by self
inside __init__
). To do so, access self.__class__
or type(self)
. So, your code may look like
class Container(object):
def __init__(self, data):
for attr in data:
setattr(type(self), attr, Item(attr))