How can I use #property.setter which was not implementet in Python 2.5.1.
Here is a example how to do it in newer versions of python.
Since I am using an older version of Python I can't really use this code.
class Info(object):
def __init__(self):
self.x = None
#property
def x(self):
return self.x
#x.setter
def x(self, value):
self.x = value
test = Info()
test.x = "It works!"
print(test.x)
Output: It works!
property in 2.5 support fget, fset and fdel, but not the #property.setter decorator.
So, two solution:
don't use property as a decorator but as a function;
create a derivated class adding them.
First solution:
class Info(object):
def __init__(self):
self._x = None
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
x = property(get_x, set_x)
Second solution:
class _property(__builtin__.property):
def getter(self, fget):
return __builtin__.property(fget, self.fset, self.fdel)
def setter(self, fset):
return __builtin__.property(self.fget, fset, self.fdel)
def deleter(self, fdel):
return __builtin__.property(self.fget, self.fset, fdel)
try:
property.getter
except AttributeError:
property = _property
Here is one way to do it.
You can use __get__ and __set__ as a replacement. This can be used in 2.5.1 or older versions of Python
class Info(object):
def __init__(self):
self.x = None
class x:
def __init__(self):
pass
def __get__(self, instance):
return instance.x
def __set__(self, instance, value):
instance.x = value
test = Info()
test.x = "It works too, in 2.5.1"
print(test.x)
Output: It works too, in 2.5.1
Related
class B:
#property
def x(self):
print('x getter')
return self.x
#x.setter
def x(self, x) -> None:
print('x setter')
self.x = x + 1
class A(B):
__instance = None
def __new__(self):
''' Virtually private constructor '''
if not A.__instance:
A.__instance = object.__new__(self)
A.__instance.__setup()
return A.__instance
def __setup(self):
self.x = 10
def minus(self):
self.x -= 3
a1 = A()
Class A is a singleton class.
I'm not sure what is causing the program to fail as there is no stack trace and it just fails.
You are not using #property and setter correctly. You need a different name for the actual underlying property:
class B:
#property
def x(self):
print('x getter')
return self._x
#x.setter
def x(self, x) -> None:
print('x setter')
self._x = x + 1
This question already has answers here:
Python class #property: use setter but evade getter?
(4 answers)
Closed 4 years ago.
class My_Class:
def __init__(self):
self._x = 0
#property
def x(self):
return self._x
#x.setter
def x(self, x):
self._x = x
If I delete the following getter from the code above:
#property
def x(self):
return self._x
The code stops working. How can I create a setter without a getter?
The property function does not have to be used as a decorator:decorator can be used as a function:
class My_Class:
def _set_x(self, value):
self._x = value
x = property(fset=_set_x) # now value has only a setter
del _set_x # optional: delete the unneeded setter function
instance = My_Class()
instance.x= 8 # the setter works
print(instance._x) # the "private" value
print(instance.x) # raises: AttributeError: unreadable attribute
class My_Class:
def __init__(self):
self._x = 0
#property
def x(self):
raise RuntimeError('This property has no getter!')
#x.setter
def x(self, x):
self._x = x
Here's an alternative answer to what I already offered: make your own write-only descriptor.
class WriteOnly:
def __init__(self, private_name):
self.private_name = private_name
def __set__(self, obj, value):
obj.__dict__[self.private_name] = value
def __get__(self, obj, type=None):
raise AttributeError('unreadable attribute')
class My_Class:
x = WriteOnly('_x')
instance = My_Class()
instance.x = 8 # the setter works
print(instance._x) # the "private" value
print(instance.x) # raises: AttributeError: unreadable attribute
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()
Why is the Property() function necessary?
Why can't I just 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.
What is a simple example of decorating a class by defining the decorator as a class?
I'm trying to achieve what has been implemented in Python 2.6 using PEP 3129 except using classes not functions as Bruce Eckel explains here.
The following works:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
def wrappedClass(*args):
return cls(*args)
return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))
def newMethod(self, value):
return value * 2
#Decorator("decorated class")
class TestClass(object):
def __init__(self):
self.name = "TestClass"
print "init %s"%self.name
def TestMethodInTestClass(self):
print "test method in test class"
def newMethod(self, value):
return value * 3
Except, in the above, wrappedClass is not a class, but a function manipulated to return a class type. I would like to write the same callable as follows:
def __call__(self, cls):
class wrappedClass(cls):
def __init__(self):
... some code here ...
return wrappedClass
How would this be done?
I'm not entirely sure what goes into """... some code here ..."""
If you want to overwrite new_method(), just do it:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
class Wrapped(cls):
classattr = self.arg
def new_method(self, value):
return value * 2
return Wrapped
#Decorator("decorated class")
class TestClass(object):
def new_method(self, value):
return value * 3
If you don't want to alter __init__(), you don't need to overwrite it.
After this, the class NormalClass becomes a ClassWrapper instance:
def decorator(decor_arg):
class ClassWrapper:
def __init__(self, cls):
self.other_class = cls
def __call__(self,*cls_ars):
other = self.other_class(*cls_ars)
other.field += decor_arg
return other
return ClassWrapper
#decorator(" is now decorated.")
class NormalClass:
def __init__(self, name):
self.field = name
def __repr__(self):
return str(self.field)
Test:
if __name__ == "__main__":
A = NormalClass('A');
B = NormalClass('B');
print A
print B
print NormalClass.__class__
Output:
A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper
Consider a base class:
class A(object):
def __init__(self, x):
self._x = x
def get_x(self):
#...
return self._x
def set_x(self, x):
#...
self._x = x
x = property(get_x, set_x)
and a derived class:
class B(A):
def set_x(self, x):
#...
self._x = x**2
x = property(A.get_x, set_x)
Is there an elegant way of overloading set_x() in class B, without re-declaring it and the property x? Thank you.
Add an extra layer of indirection (i.e. use a hook):
class A(object):
def __init__(self, x):
self._x = x
# Using a _get_hook is not strictly necessary for your problem...
def _get_hook(self):
return self._x
def get_x(self):
return self._get_hook()
# By delegating `set_x` behavior to `_set_hook`, you make it possible
# to override `_set_hook` behavior in subclass B.
def _set_hook(self, x):
self._x=x
def set_x(self, x):
self._set_hook(x)
x = property(get_x, set_x)
class B(A):
def _set_hook(self, x):
print('got here!')
self._x = x**2
b=B(5)
b.x=10
# got here!
print(b.x)
# 100
For modern versions of Python, you can also use the #property decorator:
class A(object):
#property
def x(self):
return self._get_hook()
#x.setter
def x(self, x):
self._set_hook(x)
Try this one:
class A(object):
def __init__(self):
self._x = 0
def get_x(self):
#...
return self._x
def set_x(self, x):
#...
self._x = x
x = property(get_x, lambda self,x : self.set_x(x))
class B(A):
def set_x(self, x):
#...
self._x = x**2
The extra indirection given by the lambda will make the set_x function virtually.