In class object, how to auto update attributes?
Solution 1
if updating one property due to an update on another property is what you're looking for (instead of recomputing the value of the downstream property on access) use property setters:
class SomeClass(object):
def __init__(self, n):
self.list = range(0, n)
@property
def list(self):
return self._list
@list.setter
def list(self, val):
self._list = val
self._listsquare = [x**2 for x in self._list ]
@property
def listsquare(self):
return self._listsquare
@listsquare.setter
def listsquare(self, val):
self.list = [int(pow(x, 0.5)) for x in val]
>>> c = SomeClass(5)
>>> c.listsquare
[0, 1, 4, 9, 16]
>>> c.list
[0, 1, 2, 3, 4]
>>> c.list = range(0,6)
>>> c.list
[0, 1, 2, 3, 4, 5]
>>> c.listsquare
[0, 1, 4, 9, 16, 25]
>>> c.listsquare = [x**2 for x in range(0,10)]
>>> c.list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Solution 2
Absolutely. But use a property instead.
class SomeClass(object):
def __init__(self, n=5):
self.mylist = range(n)
@property
def listsquare(self):
return [ x**2 for x in self.mylist ]
a = SomeClass()
a.mylist = [4, 5, 8]
print a.listsquare
Caching of the property value is left as an exercise for the reader.
Solution 3
Ignacio's @property solution is great but it recalculates the list every time you reference listsquare - that could get expensive. Mathew's solution is great, but now you have function calls. You can combine these with the 'property' function. Here I define a getter and a setter for my_list (I just couldn't call it 'list'!) that generates listsquare:
class SomeClass(object):
def __init__(self, n=5):
self.my_list = range(n)
def get_my_list(self):
return self._my_list
def set_my_list(self, val):
self._my_list = val
# generate listsquare when my_list is updated
self.my_listsquare = [x**2 for x in self._my_list]
# now my_list can be used as a variable
my_list = property(get_my_list, set_my_list, None, 'this list is squared')
x = SomeClass(3)
print x.my_list, x.my_listsquare
x.my_list = range(10)
print x.my_list, x.my_listsquare
This outputs:
[0, 1, 2] [0, 1, 4]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Solution 4
You can also just use setter methods, like this:
class SomeClass:
def __init__(self, n=5):
self.set_list(range(n))
def set_list(self, n):
self.list = n
self.listsquare = [ x**2 for x in self.list ]
b = SomeClass()
b.set_list(range(5,10))
Comments
-
LWZ over 3 years
I have a class which has multiple attributes that are related, for example:
class SomeClass: def __init__(self, n=0): self.list = range(n) self.listsquare = [ x**2 for x in self.list ]
If I make an object normally that would no problem, with
a = SomeClass(10)
I will get 2 lists,
a.list
anda.listsquare
.Now if I want to make a empty object first, and assign one attribute to it, I want the other attributes to be automatically updated, for example if I do
b = SomeClass() b.list = range(5,10)
I want
b.listsquare
to be automatically updated, and also the other way around (assignb.listsquare
and auto updateb.list
). Is this possible? Is Class the right choice for this?
Thanks to you all, but I'm completely overwhelmed by all the different answers. Can anyone give a complete solution so I can learn write my own?
I would like to achieve a class
Foo
with 3 attributeslength
,list
andlistsquare
such that:- If I do
a = Foo(3)
, I geta.length = 3
,a.list = [0, 1, 2]
,a.listsquare = [0, 1, 4]
. - If I do
b = Foo().list = [5, 6]
, I getb.length = 2
,b.listsquare = [25, 36]
. - If I do
c = Foo().listsquare = [4, 9]
, I getc.length = 2
,c.list = [2, 3]
.
- If I do
-
LWZ about 11 yearsGreat! What about the other way around? Can I define
a.listsquare
and geta.mylist
? -
Ignacio Vazquez-Abrams about 11 yearsYes. Just add a setter to your property.
-
LWZ about 11 yearsDoes this mean I need to define 3 properties (
size
,list
,listsquare
) so when I update one of them the other 2 will update? -
Ali-Akber Saifee about 11 yearsthat is correct. i've updated the above answer to work the way you wanted - the size attribute feel necessary anymore.
-
tdelaney about 11 yearsthanks to the folks pointing out i had initialized the list incorrectly.