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."
6
7 def Property(func):
8 return property(**func())
9
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()
Property() function necessary?return locals() and then use @property as a decorator directly?When I do that I get an error saying x takes no arguments, one given (presumably 'self'). I know python has the @x.setter option, however I'm forced to use 2.4 regularly, so it's not an option for me. Even then, @x.setter still seems less elegant than defining it all in one block.
Is there a way to define it all in one block using @property?
You can't use property as a decorator directly for the code you have posted because it was not designed to be used that way, and it won't work.
If used as a decorator, property converts the function into the getter; if used as a function, you can pass in the getter, setter, deleter, and a doc.
locals() returns all the locals, so you would have a dictionary with fget, fset, fdel, doc, Property, and __init__ -- causing property to blow up because it was passed too many arguments.
Personally, I like the @x.setter and @x.deleter style, as I don't end up with unnecessary function names in the class name space.
If you have to use 2.4 regularly, just roll your own (or steal the latest from 2.6 like I did ;):
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")
self.fdel(obj)
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: not by using @property by defining and instantiating a class that has __get__(), __set__(), and __delete__() methods. 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()
property() is a shortcut for writing the above, and the Property() method in your example class is a shortcut for having to write the functions separately and pass them to property(); instead you write a function that defines the functions, then returns them, where they get passed to property().
The reason you can't use @property is that decorators decorate a single object. So you'd need a container, such as a class, and so you might as well just write a descriptor directly at that point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With