Python property decorators and set functions

I have some questions regarding the following code:

  1 class Test(object):
  2     def __init__(self):
  3         print "Object instance created."
  4         self._x = raw_input("Initial value of x = ")
  5         print "Initial value of x set."
  7     def Property(func):
  8         return property(**func())
 10     @Property
 11     def x():
 12         def fget(self):
 13             print 'Getting x'
 14             return self._x
 15         def fset(self, val):
 16             print 'Setting x'
 17             self._x = val
 18         def fdel(self):
 19             print 'Deleting x'
 20             del self._x
 21         doc = "A test case"
 22         return locals()


  • Why is a function needed Property()

  • Why can't I just return locals()

    and then use @property

    as a decorator directly?

When I do this, I get the error: x takes no arguments, one of them (presumably "i"). I know python has an option @x.setter

, however I am forced to use 2.4 regularly so this is not an option for me. Even then @x.setter

, it still seems less elegant than defining just one block.

Is there a way to define it all in one block with @property



source to share

2 answers

You cannot use property

as a decorator directly for the code you posted as it is not intended to be used in this way and it will not work.

If used as a decorator, property

converts the function to a getter; if used as a function, you can pass to receiver, setter, deleter and doc.


It returns all locales, so you will have a dictionary with fget

, fset

, fdel

, doc

, property

and __init__

that will lead to the removal property

because it was passed too many arguments.

Personally, I like the style @x.setter

and @x.deleter

since I have no extra function names in the class namespace.

If you need to use 2.4 regularly, just roll your own (or steal the latest from 2.6 like me;):

    class property(object):
        "2.6 properties for 2.5-"    
        def __init__(self, fget=None, fset=None, fdel=None, doc=None):
            self.fget = fget
            self.fset = fset
            self.fdel = fdel
            self.__doc__ = doc or fget.__doc__
        def __call__(self, func):
            self.fget = func
            if not self.__doc__:
                self.__doc__ = fget.__doc__
        def __get__(self, obj, objtype=None):
            if obj is None:
                return self         
            if self.fget is None:
                raise AttributeError("unreadable attribute")
            return self.fget(obj)
        def __set__(self, obj, value):
            if self.fset is None:
                raise AttributeError("can't set attribute")
            self.fset(obj, value)
        def __delete__(self, obj):
            if self.fdel is None:
                raise AttributeError("can't delete attribute")
        def setter(self, func):
            self.fset = func
            return self
        def deleter(self, func):
            self.fdel = func
            return self




You can do it all in one block: without using @property

, defining and instantiating a class with methods __get__()

, __set__()

and __delete__()

. See Implementing Descriptors for more details :

class Test(object):
    def __init__(self):
        print "Object instance created."
        self._x = raw_input("Initial value of x = ")
        print "Initial value of x set."
    class x(object):
        def __get__(self, instance, owner):
            print 'Getting x'
            return instance._x
        def __set__(self, instance, value):
            print 'Setting x'
            instance._x = value
        def __delete__(self, instance):
            print 'Deleting x'
            del instance._x
        __doc__ = "A test case"
    x = x()



is a shortcut for writing the above, and a method property()

in your example class is a shortcut for writing functions separately and passing them to property()

; instead, you write a function that defines the functions and then returns them where they are passed to property()


The reason you can't use @property

is because decorators decorate a single object. So you need a container, like a class, and so you can just write the handle directly at this point.



All Articles