[Python-Dev] Definining properties - a use case for class decorators?

Nick Coghlan ncoghlan at iinet.net.au
Sun Oct 16 15:56:10 CEST 2005


On and off, I've been looking for an elegant way to handle properties using 
decorators.

It hasn't really worked, because decorators are inherently single function, 
and properties span multiple functions.

However, it occurred to me that Python already contains a construct for 
grouping multiple related functions together: classes.

And that thought led me to this decorator:

   def def_property(cls_func):
       cls = cls_func()
       try:
           fget = cls.get.im_func
       except AttributeError:
           fget = None
       try:
           fset = cls.set.im_func
       except AttributeError:
           fset = None
       try:
           fdel = cls.delete.im_func
       except AttributeError:
           fdel = None
       return property(fget, fset, fdel, cls.__doc__)

Obviously, this decorator can only be used by decorating a function that 
returns the class of interest:

   class Demo(object):
      @def_property
      def test():
          class prop:
              """This is a test property"""
              def get(self):
                  print "Getting attribute on instance"
              def set(self, value):
                  print "Setting attribute on instance"
              def delete(self):
                  print "Deleting attribute on instance"
          return prop

Which gives the following behaviour:

Py> Demo.test
<property object at 0x00B9CC38>
Py> Demo().test
Getting attribute on instance
Py> Demo().test = 1
Setting attribute on instance
Py> del Demo().test
Deleting attribute on instance
Py> help(Demo.test)
Help on property:

     This is a test property

     <get> = get(self)

     <set> = set(self, value)

     <delete> = delete(self)

If we had class decorators, though, the decorator could be modified to skip 
the function invocation:

   def def_property(cls):
       try:
           fget = cls.get.im_func
       except AttributeError:
           fget = None
       try:
           fset = cls.set.im_func
       except AttributeError:
           fset = None
       try:
           fdel = cls.delete.im_func
       except AttributeError:
           fdel = None
       return property(fget, fset, fdel, cls.__doc__)

And the usage would be much more direct:

   class Demo(object):
      @def_property
      class test:
          """This is a test property"""
          def get(self):
              print "Getting attribute on instance"
          def set(self, value):
              print "Setting attribute on instance"
          def delete(self):
              print "Deleting attribute on instance"


Comments? Screams of horror?

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.blogspot.com


More information about the Python-Dev mailing list