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
Related
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
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.
We have some variable, or other instance: a='?'.
We have such input:
f = a(3112).bas(443).ssad(34)
When we type
print(f)
Output should be:
3112a-443bas-34ssad
I've tried some ways to solve this and have found information about chaining, but I still have the problem. I can't return class name to the brginning of the string.
This, what I have:
class A():
def __getattribute__(self, item):
print (str(item))
return super(A, self).__getattribute__(item)
def __init__(self, x):
self.x = x
print (str(x))
def b(self, item):
print (str(item))
return self
def c(self, item):
print (str(item))
return self
def d(self, item):
print (str(item))
return self
A(100).b(200).c(300).d(400)
My output:
100
b
200
c
300
d
400
But I couldn't concatenate it in one string.
Dynamic way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def __getattr__(self, attrname, *args):
def wrapper(*args, **kwargs):
self._strings.append('{}{}'.format(args[0], attrname))
return self
return wrapper
def __str__(self):
return '-'.join(self._strings)
print(A(100).bas(200).ssad(300))
Output
100a-200bas-300ssad
But also
print(A(100).egg(200).bacon(300).SPAM(1000))
Output
100a-200egg-300bacon-1000SPAM
Static way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def bas(self, integer):
self._strings.append('{}bas'.format(integer))
return self
def ssad(self, integer):
self._strings.append('{}ssad'.format(integer))
return self
def __str__(self):
return '-'.join(self._strings)
print(A(100).b(200).c(300))
Output
100a-200bas-300ssad
More about __str__
You can override the __str__ method to define your specific output:
class A():
def __init__(self, a, b="", c="", d=""):
self._a = a
self._b = b
self._c = c
self._d = d
def __str__(self):
return '{}a-{}b-{}c-{}d'.format( self.a, self.b, self.c, self.d )
def b(self, item):
self._b = item
return self
def c(self, item):
self._c = item
return self
def d(self, item):
self._d = item
return self
f = A(100).b(200).c(300).d(400)
print(f) # 100a-200b-300c-400d
Here I tried it in another way , ie, If you want to take the function name instead of manually giving it you can use inspect in python. Try this code :
import inspect
class A():
l = []
def __init__(self, x):
self.x = x
print (str(x))
self.l.append(str(x) + "a")
def b(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def c(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def d(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
print("-".join(A(100).b(200).c(300).d(400).l))
The o/p is like :
'100a-200b-300c-400d'
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 ?
Could anyone find a problem with this #property decorator? I cannot seem to get it to assert correctly. I'm sure I'm doing some really simple thing wrong, but can anyone point my tired eyes in the right direction please?
class A:
def __init__(self):
self.a = 0
self._b = 0
#property
def b(self):
return self.b
#b.getter
def b(self):
if self._b is None:
return 0
return self._b
#b.setter
def b(self, val):
self._b = (val * 20)
def test_getter_setter():
obj = A()
obj.a = 1
#obj.b = 2
print obj.a, obj.b
obj.b = 2
print obj.a, obj.b
assert obj.b == 40
test_getter_setter()
The #property decorator only works on new style classes. Inherit from object:
class A(object):
With that change your test function passes.