"Data" vs. "Non-data" Descriptors in PEP 252, and "once" attributes
Phillip J. Eby
pje at telecommunity.com
Sun Feb 24 22:01:25 EST 2002
One nice feature of 2.2 is that you can define attribute descriptors in
Python. I've found a way to use this to create "once" attributes:
instance attributes which are computed once per instance, with the value
cached from that point on. Here's an example::
class once(object):
def __init__(self,name,func):
self.name = name
self.func = func
def __get__(self, ob, typ=None):
if ob is not None:
value = self.func(ob)
ob.__dict__[self.name]= value
return value
class aThing(object):
def anAttr(self):
print "computing anAttr"
return 100*100
anAttr = once('anAttr', anAttr)
thing = aThing()
# prints "computing anAttr", then 10000
print thing.anAttr
# just prints 10000 the second time
print thing.anAttr
Interestingly, this does *not* work if you try to do something similar
with the built-in 'property' type. Apparently, 'property' is considered
a data descriptor, while the above 'once' type is considered a "non-data"
descriptor.
Does anyone know if this usage is safe for future Python versions? In
another variation of this, I use a metaclass to make classes that
automatically instantiate themselves inside of a containing class, e.g::
class onceClass(type):
def __get__(klass, ob, typ=None):
if ob is not None:
instance = klass(ob)
ob.__dict__[klass.__name__] = instance
return instance
class Outer(object):
class Inner:
__metaclass__ = onceClass
def __init__(self, ctx):
print "creating Inner, bound to", ctx
anOuter = Outer()
# prints creation message, then the inner object
print anOuter.Inner
# just prints the inner object
print anOuter.Inner
This sort of thing is handy for when you have complex (but relatively
static) object structures that need to be built up. I imagine it will
come in especially handy for GUI programming, but I haven't actually used
it for that yet.
Anyway, I'd like to be sure I'm not doing anything which is "unsafe" for
future versions. Although PEP 252 spells out most of the rules quite
clearly, there is one bit of ambiguity: the definition of "data" versus
"non-data" descriptors. To be precise, it doesn't really define the
difference. The 2.2 source operationally defines a data descriptor as
one which has a 'tp_descr_set' slot value, and new-style classes don't
set that slot unless you supply a '__set__' method. (Interestingly,
'__delete__' is ignored for slot setup purposes, and supplying
'__delete__' without a '__set__' still results in a "non-data"
descriptor.
Operationally, it seems it would be hard to change any of this in a way
that would break my "once" examples without also breaking lots of other
things. But the PEP doesn't really give an official way to create either
a data or non-data descriptor; it just says what the current
implementation does. Hence my concern.
Of course, if upon reading this, lots of people think that "once"
attributes are cool and start using it, I suppose it'll become a backward
compatibility issue for more than just me. :)
More information about the Python-list
mailing list