Calling a method in setter in python - python

I want to implement a class property that is computed from other properties.
class Sum(object):
#property
def a(self):
return self._a
#a.setter
def a(self, val):
self._a = a
self._constructSeries()
#property
def b(self):
return self._b
#b.setter
def b(self, val):
self._b = b
self._constructSeries()
def _constructSeries(self):
# Some calculations involving a and b
self._series = function(a, b)
def __init__(self, a, b):
self.a = a
self.b = b
One way I know of is to define series as a property
#property
def series(self):
return fun(a,b)
But I want to avoid calling fun each and every time as it takes a lot of computations. What is the standard way to handle such a case?

If I got it right you want to be able to change a and b without computing the fun everytime but when you request the result of the fun is the most updated one, is it correct?
In such a case you can use property
def get_series(self):
if self._series is None or self.updated is False:
self._series = fun(self.a,self.b)
self.updated = True
return self._series
series = property(get_series)
And when you set a and b you update the flag
#property
def a(self):
self.updated = False
return self._a
#property
def b(self):
self.updated = False
return self._b
Then self.series returns the updated values but it runs fun just if the input changes from the last time it has been computed.

Related

getting RecursionError when using Getter and Setter decorators [duplicate]

Can somebody tell me why there is a recursion in the following code ?
class A:
def __init__(self):
self.a = 0
#property
def a(self):
print ("called a getter")
return self.a
#a.setter
def a(self, value):
print ("called a setter")
self.a = value
class B(A):
def check(self):
a = 10
if __name__ == "__main__":
bb = B()
bb.check()
I have to call a base class setter from child class. I am not allowed to access the member directly. Can somebody tell me how to do other way ?
#a.setter
def a(self, value):
print ("called a setter")
self.a = value
When self.a = value executes, it calls your method a(self, value) again, which executes self.a = value again, which calls a(self, value)... etc.
The conventional solution is to have different names for the property and the underlying attribute. Ex. you can add an underscore to the front.
class A:
def __init__(self):
self._a = 0
#property
def a(self):
print ("called a getter")
return self._a
#a.setter
def a(self, value):
print ("called a setter")
self._a = value

Conditions on class parameters

I am creating a Class qubit which has 2 parameters: a and b. I want to make sure everytime user changes parameters, the condition a^2 +b^2=1 must hold . If the condition does not hold then it is an invalid input.
A related Problem: Is there a way to run some function update() everytime the user changes parameters?
class Qubit(object):
def __init__(self):
self.a = 1
self.b = 0
Sure thing. Use propertys so you get getter/setter behavior:
class Qubit(object):
def __init__(self, a=1, b=0):
self._validate(a, b)
self._a = a
self._b = b
#staticmethod
def _validate(a, b):
if a ** 2 + b ** 2 != 1:
raise ValueError('{}^2 + {}^2 != 1'.format(a, b))
# Getter for `a`
#property
def a(self):
return self._a
# Setter for `a`
#a.setter
def a(self, value):
self._validate(a=value, b=self._b)
self._a = value
# (Repeat for `b`.)

Function decorator that will return self?

I have to following class that will make an object with chainable methods that derive from class variables. Since this code is quite repetitive, my challenge is to make a decorator that can apply over method a, b and c. The problem I am facing is that I cannot seem to find a way to construct a wrapper that will return the instance (self). Is there a better way to construct this?
class Test:
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
self.call_chain = []
def a(self, truth):
def func():
return self._a == truth
self.call_chain.append(func)
return self
def b(self, truth):
def func():
return self._b == truth
self.call_chain.append(func)
return self
def c(self, val):
def func():
return self._c == val
self.call_chain.append(func)
return self
def evaluate(self):
try:
for f in self.call_chain:
if f() == False:
raise ValueError('False encountered')
except ValueError:
self.call_chain.clear()
return False
self.call_chain.clear()
return True
It works chained like this:
c = Test(True, False, 13)
c.a(True).b(False).c(13).evaluate()
The trick is to store the arguments to the function as part of the call chain. The easiest way is to use functools.partial objects.
from functools import wraps, partial
def chain(func):
#wraps(func)
def wrapper(self, *args, **kwargs):
suspended = partial(func, self, *args, **kwargs)
self.call_chain.append(suspended)
return self
return wrapper
class Test:
def __init__(self, a, b, c):
self.call_chain = []
self._a = a
self._b = b
self._c = c
#chain
def a(self, val):
return self._a == val
#chain
def b(self, val):
return self._b == val
#chain
def c(self, val):
return self._c == val
def evaluate(self):
try:
for f in self.call_chain:
if f() == False:
raise ValueError('False encountered')
except ValueError:
self.call_chain.clear()
return False
self.call_chain.clear()
return True
c = Test(True, False, 13)
c.a(True).b(False).c(13).evaluate() # True
c.a(True).b(False).c(11).evaluate() # False

Dependent properties that are CPU intensive

I am very often confronted to this case and did not manage to discover a stable way to deal with it.
Suppose I have a class defined like that:
class MyClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
#property
def c(self):
"""This method performs some heavy computations based on a and b properties"""
# Some heavy computations only with a and b attributes
return c
Property c may be now be retrieved by:
>>> obj = MyClass(a, b)
>>> print obj.c
However, every time I ask for obj.c, the heavy computations will be performed, resulting in a poor performance code as c results from heavy computations and it would preferably be calculated only while a or b is set or modified.
What would the better way to deal with this case ? I am thinking of creating a c_update method to use as a decorator for some #a.setter and #b.setter decorated methods but is that the better way ?
Regards,
But what if I have a lot of XX dependent properties that rely on a and b values. Do I have to write an update_XX method for each of them and add this method to init and to each a.setter and b.setter ? That seems to me quite verbose...
You can have the c value (and any other number of dependent properties) updated everytime either a or b is mutated, I implemented an update_properties() method below:
class MyClass(object):
def __init__(self, a, b):
self._a = a
self._b = b
self.update_properties()
#property
def a(self):
return self.a
#a.setter
def a(self, value):
self._a = value
self.update_properties()
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value
self.update_properties()
def update_properties(self):
self.c = self._a + self._b
self.d = self._a * self._b
self.e = self._a - self._b
# self.f = ...
# ...
# self.z = ...
# Can go on as long as you want
Do you think it would be possible to implement this machinery as some decorators in order to lighten the code
The verbosity seems to be only on the side that tracks the free variables (e.g. here a and b), so if I had to support an arbitrary number of those, I would implement a MyClass.set_value(name, value)
def set_value(self, name, value):
setattr(self, name, value)
self.update_properties()
So the idea here is that our set_value() can work with an arbitrary number of attributes. And it's possible to call it from __init__ if you use **kwargs to unpack the key-values passed to the constructor.
One requirement here, since we haven't set the free variables as #property we're required to use obj.set_value('a', 42) instead of obj.a = 42
There is a small pypi package that fits well: cached-property
from cached_property import cached_property
class MyClass(object):
def __init__(self):
pass
#cached_property
def c(self):
# Heavy computation based on self.a / self.b
return ...
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
del self.c
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value
del self.c
Of course you could also build an abstraction for the a/b properties on top of that, that utilizes del self.c.
One benefit of using cached_property is that you can easily make the cache thread-safe by changing it to threaded_cached_property.
I'd simply store the actual value of c in a private attribute and check if this is not None. Set this to None when either a or b changes.
So the "proper" way of doing this using properties would be:
class MyClass(object):
def __init__(self, a, b):
self._a = a
self._b = b
self._c = None
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
self._c = None
#property
def b(self):
return self._b
#b.setter
def a(self, value):
self._b = value
self._c = None
#property
def c(self):
if self._c is None:
self._c = # compute c here
return self._c
If you want to avoid creating all these properties and setters you probably want to hijack the __getattr__ and __setattr__ methods instead:
class MyClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
self._c = None
def __getattr__(self, name):
if name == 'c':
if self._c is None:
self._c = # compute c here
return self._c
raise AttributeError(name)
def __setattr__(self, name, value):
if name == 'c':
raise TypeError('You cannot modify property c directly')
super(MyClass, self).__setattr__(name, value)
if name in ('a', 'b'):
super(MyClass, self).__setattr__('_c', None)
Note that this last solution could be extended to like 10 attributes a1, ..., a10 without having to define 10 properties and setters.
It's probably a bit less robust.
So based on your answers, I managed to build a new answer using a dict for dependent properties.
class MyClass(object):
def __init__(self, a, b):
self._properties = dict()
self._a = a
self._b = b
def _update_dependent_properties(self):
# Do computations for c1, c2...
self._properties['c1'] = # c1 value
self._properties['c2'] = # c2 value
# ...
#property
def a(self):
return self._a
#property
def b(self):
return self._b
#a.setter
def a(self, value):
self._properties.clean()
self._a = value
#b.setter
def b(self, value):
self._properties.clean()
self._b = value
#property
def c1(self):
try:
return self._properties['c1']
except KeyError:
_update_dependent_properties()
return self._properties['c1']
#property
def c2(self):
try:
return self._properties['c2']
except KeyError:
_update_dependent_properties()
return self._properties['c2']
This seem to do the trick but it is still quite verbose... and I have still to write a property for each of the dependent property I am expecting. However, it does force the calculation of update_dependent_properties() when either attribute a or b is modidied.
I wonder if it does not exist a module to do it. It seem that my problem sounds like memoize technique... and may a decorator lighten the code by systematizing the procedure ?

pythonic class instance attribute calculated from other attributes

I have a class instance with attributes that are calculated from other attributes. The attributes will change throughout the life of the instance. All attributes are not necessarily defined when the object is initialized.
what is the pythonic way to calculate attributes from other attributes?
This is a simple example, the calculations have numerous input variables ("a" below) and calculations ("b" & "c").
a = something
b = function of a (a+5)
c = function of a and b (a*b)
I've tried numerous implementations. Here is a decent one to communicate my intention.
class CalcAttr(object):
def __init__(self):
self._a = None
self._b = None
self._c = None
#property
def a(self):
return self._a
#a.setter
def a(self,value):
self._a = value
#property
def b(self):
self.calc_b()
return self._b
#property
def c(self):
self.calc_c()
return self._c
def calc_b(self):
self._b = self._a + 5
def calc_c(self):
self._c = self._a * self._b
def test():
abc = CalcAttr()
a = 5
return abc.c
Note: t.c works if I first call t.b first.
> >>> t=abc.test()
> >>> t.c Traceback (most recent call last): File "<stdin>", line 1, in <module> File "abc.py", line 22, in c
> self.calc_c() File "abc.py", line 29, in calc_c
> self._c = int(self._a) * int(self._b) TypeError: int() argument must be a string or a number, not 'NoneType'
> >>> t.b 10
> >>> t.c 50
> >>>
Keep in mind most of the real calculations are dependent on multiple attribures (5-10 input variables & as many calculated ones).
My next iteration will include a "calculate_model" function that will populate all calculated attributes after checking that all inputs are defined. Maybe that will be the pyhonic answer?
Thanks!
Update - working solution
I created a method that calculates each attribute in order:
def calc_model(self):
self.calc_b()
self.calc_c()
Each calculated attribute calls that method
#property
def c(self):
self.calc_model()
return self._c
I'm not sure if this is proper, but it works as desired...
If I understand your question correctly, you should compute b and c in their getters. You should also probably require that the user passes a value for a in the initializer, since b and c can't be computed without a. Also, it doesn't seem like there is much of a reason to keep _a, _b, and _c around -- unless b and c are expensive to compute and you'd like to cache them.
For example:
class CalcAttr(object):
def __init__(self, a):
self.a = a
#property
def b(self):
return self.a + 5
#property
def c(self):
return self.a * self.b
Such that
>>> x = CalcAttr(42)
>>> x.c
1974
I understand what #jme suggested in the accepted answer is more elegant, but I still try to fix the original example and get it to work. Here is the code.
class CalcAttr(object):
def __init__(self):
self._a = None
self._b = None
self._c = None
#property
def a(self):
return self._a
#a.setter
def a(self,value):
self._a = value
#property
def b(self):
self.calc_b()
return self._b
#property
def c(self):
self.calc_c()
return self._c
def calc_b(self):
self._b = self._a + 5
def calc_c(self):
self._c = self.a * self.b
def test():
abc = CalcAttr()
abc.a = 5
return abc.c
test()
The code will work and 50 is the resulted value.

Categories