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
Related
Is it possible to override a property in a base class by a regular attribute in a derived class, something like this:
class A(object):
#property
def x(self):
return self._x
#x.setter
def x(self, y):
self._x = y
class B(A):
def __init__(self, y):
self.x = y #the descriptor methods are not called and
#"x" is a regular attribute in the object dict.
The reason I am asking is because I have a complex base class in which one of the descriptor attributes typically performs a complicated calculation. However, in one of the derived classes, the returned value is trivial and it seems like a waste to have to override with another descriptor and not just a regular storage attribute.
You can simply redeclare x in B:
class A(object):
#property
def x(self):
print("calculating x...")
return self._x
#x.setter
def x(self, y):
print('setting x...')
self._x = 10*y
class B(A):
x = None
def __init__(self, y):
self.x = y #the descriptor methods are not called and
#"x" is a regular attribute in the object dict.
b = B(3)
print(b.x)
# 3
In tutorials I have seen two types of instance attribute naming for the purpose of using #property. Here is code showing examples of both. They also seem to work differently.
class A:
def __init__(self, x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x > 1000:
self.__x = 1000
else:
self.__x = x # Instance attribute __x defined outside __init__
class B:
def __init__(self, x):
self._x = x
#property
def x(self):
return self._x
#x.setter
def x(self, x):
if x > 1000:
self._x = 1000
else:
self._x = x
a = A(9999)
print(a.x) # -> 1000
b = B(9999) # -> 9999
print(b.x)
b.x = 9999
print(b.x) # -> 1000
I like the behaviour of class A better as it seems that the #x.setter is used immediately in __init__, however that piece of code gives me a warning in PyCharm (I have it as a comment). Why would there be a warning if that is the proper use of a Python's property setter? There are no warnings in class B. Could I somehow call #x.setter in __init__ the same way as in class A without a warning?
It seems to be a bug in PyCharm: https://youtrack.jetbrains.com/issue/PY-25263.
A temporary solution I found was to add self._x = None in the __init__. So the code would be:
class A:
def __init__(self, x):
self._x = None
self.x = x
#property
def x(self):
return self._x
#x.setter
def x(self, x):
if x > 1000:
self._x = 1000
else:
self._x = x
a = A(9999)
print(a.x) # -> 1000
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
This question already has answers here:
Understanding __get__ and __set__ and Python descriptors
(8 answers)
Closed 8 years ago.
Is there a function such that i can write but as a function?
class foo:
def __init__(self,x):
self.x = x;
asd = foo(2);
asd.x = 5;
print(asd.x);
But like:
class foo:
def __init__(self,x):
self.x = x;
def someFunction(self,string,value):
if(string == 'x'):
self.x = value;
print("worked");
asd = foo(2);
asd.x = 3; #and "worked" will be printed?
I tried __ set __ and __ setattr __ but i had no luck ;\
Is there a way to call a function when setting a class variable?
asd.x = 3; calls a function?
Use a property. The method decorated by #property will be used whenever you try to access the attribute x; the method subsequently decorated by #x.setter will be called whenever you try to set the value of x. The underlying "private" attribute _x is used to store the value for x used by both the getter and setter.
class foo:
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
print("worked")
def __init__(self, x):
self._x = x
The decorator syntax can be skipped if you want more explicit names for the getter and setter methods:
class foo(object):
def __init__(self, x):
self._x = x
def _get_x(self):
return self._x
def _set_x(self, value):
self._x = value
print("worked")
x = property(_get_x, _set_x)
For an object to handle setting of attributes on itself, use the __setattr__ method. It's rather tricky to debug, so don't do this unless you know what you're doing. Good explanation
source
class Beer(object):
def __init__(self, adj):
self.adj = adj
def __setattr__(self, key, value):
print '\tSET',key,value
object.__setattr__(self, key, value) # new style (don't use __dict__)
b = Beer('tasty')
print 'BEFORE',b.adj
b.adj = 'warm'
print 'AFTER',b.adj
print b.__dict__
output
SET adj tasty
BEFORE tasty
SET adj warm
AFTER warm
{'adj': 'warm'}
In C-ish languages, I'd mask data storage details with getter/setter methods/functions like:
int getFoo();
void setFoo(int value);
I have some Python that does:
class MyClass:
def Foo(self):
...magic to access foo...
return value
What's the right way to write/name a setter for Foo? I'm sure it's more idiom than language feature but I'm not sure what's common. Maybe I need to rename Foo() to getFoo() and match it with setFoo(). I guess that's OK if that's what is usually done.
You can use a property. This is pulled directly from the docs:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
Now you can do...
c = C()
c.x = "a"
print c.x
>>> "a"
del c.x
Keep in mind that in Python versions prior to Python 3 (e.g., Python 2.7) you need to make sure that your object is a new-style class (it must derive from object) for it to support properties like this. Granted, you probably should be using new-style classes for all your classes anyway...
Use the builtin property function:
class MyClass:
def __init__(self):
self._value = 'Initialize self._value with some value or None'
def get_foo(self):
...magic to access foo...
return self._value
def set_foo(self, value):
... magic processing for value ...
self._value = value
foo = property(get_foo, set_foo)
Now you can use access it like this:
inst = MyClass()
inst.foo = 'Some value'
print inst.foo
It will print:
'Some value'
Generally you don't need to use getters and setters in Python.
If however, you want to expose the result of a procedure as a property, you can use the #property decorator:
class MyClass:
#property
def foo(self):
# operation
return value
#foo.setter
def foo(self, value):
# operation storing value
It is more common to just store the value of foo in an attribute. This can be calculated in the __init__ instance initializer:
class MyClass:
def __init__(self):
self.foo = someCalculationDeterminingFoo()