On 10 Jul 2005 13:38:22 -0700, "George Sakkis" <[EMAIL PROTECTED]> wrote:
>I'm trying to write a decorator similar to property, with the >difference that it applies to the defining class (and its subclasses) >instead of its instances. This would provide, among others, a way to >define the equivalent of class-level constants: > >class Foo(object): > @classproperty > def TheAnswer(cls): > return "The Answer according to %s is 42" % cls.__name__ > >>>> Foo.TheAnswer >The Answer according to Foo is 42 >>> Foo.TheAnswer = 0 >exceptions.AttributeError >... >AttributeError: can't set class attribute > >I read the 'How-To Guide for Descriptors' >(http://users.rcn.com/python/download/Descriptor.htm) that describes >the equivalent python implementation of property() and classmethod() >and I came up with this: > >def classproperty(function): > class Descriptor(object): > def __get__(self, obj, objtype): > return function(objtype) > def __set__(self, obj, value): > raise AttributeError, "can't set class attribute" > return Descriptor() > >Accessing Foo.TheAnswer works as expected, however __set__ is >apparently not called because no exception is thrown when setting >Foo.TheAnswer. What am I missing here ? > I suspect type(Foo).TheAnswer is not found and therefore TheAnswer.__set__ is not looked for, and therefore it becomes an ordinary attribute setting. I suspect this is implemented in object.__setattr__ or type.__setattr__ as the case may be, when they are inherited. So I introduced a __setattr__ in type(Foo) by giving Foo a metaclass as its type(Foo). First I checked whether the attribute type name was 'Descriptor' (not very general ;-) and raised an attribute error if so. Then I made a class Bar version of Foo and checked for __set__ and called that as if a property of type(Bar) instances. See below. ----< classprop.py >---------------------------------------------------- def classproperty(function): class Descriptor(object): def __get__(self, obj, objtype): return function(objtype) def __set__(self, obj, value): raise AttributeError, "can't set class attribute" return Descriptor() class Foo(object): class __metaclass__(type): def __setattr__(cls, name, value): if type(cls.__dict__.get(name)).__name__ == 'Descriptor': raise AttributeError, 'setting Foo.%s to %r is not allowed' %(name, value) type.__setattr__(cls, name, value) @classproperty def TheAnswer(cls): return "The Answer according to %s is 42" % cls.__name__ @classproperty def AnotherAnswer(cls): return "Another Answer according to %s is 43" % cls.__name__ class Bar(object): class __metaclass__(type): def __setattr__(cls, name, value): attr = cls.__dict__.get(name) if hasattr(attr, '__set__'): attr.__set__(cls, value) # like an instance attr setting else: type.__setattr__(cls, name, value) @classproperty def TheAnswer(cls): return "The Answer according to %s is 42" % cls.__name__ @classproperty def AnotherAnswer(cls): return "Another Answer according to %s is 43" % cls.__name__ if __name__ == '__main__': print Foo.TheAnswer Foo.notTheAnswer = 'ok' print 'Foo.notTheAnswer is %r' % Foo.notTheAnswer print Foo.AnotherAnswer try: Foo.TheAnswer = 123 except AttributeError, e: print '%s: %s' %(e.__class__.__name__, e) try: Foo.AnotherAnswer = 456 except AttributeError, e: print '%s: %s' %(e.__class__.__name__, e) print Bar.TheAnswer Bar.notTheAnswer = 'ok' print 'Bar.notTheAnswer is %r' % Bar.notTheAnswer print Bar.AnotherAnswer try: Bar.TheAnswer = 123 except AttributeError, e: print '%s: %s' %(e.__class__.__name__, e) try: Bar.AnotherAnswer = 456 except AttributeError, e: print '%s: %s' %(e.__class__.__name__, e) ------------------------------------------------------------------------ Result: [18:17] C:\pywk\clp>py24 classprop.py The Answer according to Foo is 42 Foo.notTheAnswer is 'ok' Another Answer according to Foo is 43 AttributeError: setting Foo.TheAnswer to 123 is not allowed AttributeError: setting Foo.AnotherAnswer to 456 is not allowed The Answer according to Bar is 42 Bar.notTheAnswer is 'ok' Another Answer according to Bar is 43 AttributeError: can't set class attribute AttributeError: can't set class attribute Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list