Reputation: 2431
I am extremely new to Python (coming from JavaScript) and I am battling with understanding how to change a value of a class variable. All I am trying to do is to change the age value, and then display the new msg
. But when I add Tester.age = 20
it doesn't change my msg
output. My msg
output still uses age = 10
.
How do I change a class variable externally?
class ClassTester:
age = 10
seconds = age * 365 * 24 * 60 * 60
msg = "You have lived for " + str(seconds) + " seconds."
Tester = ClassTester()
Tester.age = 20
print(Tester.msg)
Upvotes: 2
Views: 11850
Reputation: 389
Old question, but still deserves a new answer.
It seems that what the OP wanted was to somehow change the value of a class variable in a way that the change could be felt by all objects of the class.
You can´t do it directly changing the value of the class variable, but if the value of the class variable is a mutable object then you can change the content of that object instead and the change will be seem by all instances of the class.
class A:
my_magic = dict()
a = A()
b = A()
c = A()
a.my_magic['x'] = "something"
b.my_magic['y'] = "other thing"
print(c.my_magic)
results
{'x': 'something', 'y': 'other thing'}
Upvotes: 0
Reputation: 487
First, as was pointed out in comments, you should declare variables in __init__
constructor. As to your example, I'd suggest to make some more advanced steps, so consider following: you actually have only one important variable, which is self.age
. Everything else is derived from it, and so you can lose consistency: for example, when changing self.age
another variables will not be changed. Also, you can later on in your project change self.seconds
variable, thus completely messing up your class instance. To solve that, have a look at property
decorator:
class ClassTester:
def __init__(self, age=10):
self.age = age
@property
def seconds(self):
return self.age * 365 * 24 * 60 * 60
@property
def msg(self):
return "You have lived for {} seconds.".format(self.seconds)
There, @property
is a handy decorator, which allows you to do address seconds
and msg
as attributes, but which will be always synced and consistent: first, you cannot set seconds
attribute, thus it is protected. Second, changing age
will affect all subsequent calls to msg
and seconds
.
Example usage:
>>> tester = ClassTester()
>>> tester.seconds
315360000
>>> tester.msg
'You have lived for 315360000 seconds.'
>>> tester.age = 23
>>> tester.seconds
725328000
>>> tester.msg
There is a lot more about @property
, feel free to explore! For example, see this answer for some in-depth @property
analysis.
Upvotes: 0
Reputation: 2431
The solution is to set the variables in an object-level (not class-level). You do this by creating the variables inside the init area like below. You can then change the values externally.
Then you need to calculate whatever you want in a different function, using that variable. Then just call that function where you need it.
VERY IMPORTANT (the mistake I made): The init is written with TWO underscores _ x 2 on each side
class ClassTester:
def __init__(self):
self.age = 10
def msg(self):
self.seconds = self.age * 365 * 24 * 60 * 60
self.txt = "You have lived for " + str(self.seconds) + " seconds."
return self.txt
Tester = ClassTester()
Tester.age = 20
print(Tester.msg())
Tester.age = 30
print(Tester.msg())
Upvotes: 1
Reputation: 5101
I recommend using properties, so your interface would not change.
class ClassTester:
def __init__(self):
self._age = 10
self._msg = "You have lived for {} seconds."
self._secs = self._seconds(self._age)
@staticmethod
def _seconds(age):
return age * 365 * 24 * 60 * 60
@property
def age(self):
return self._age
@age.setter
def age(self, v):
self._age = v
self._secs = self._seconds(v)
@property
def msg(self):
return self._msg.format(self._secs)
Tester = ClassTester()
print(Tester.msg) # You have lived for 315360000 seconds.
Tester.age = 20
print(Tester.msg) # You have lived for 630720000 seconds.
EDIT:
I added a static method to recalculate the seconds value and call that from the __init__
and the age setter to reduce recalculations as per the OP's concern about those in the comment to another answer
Upvotes: 3
Reputation: 4420
age is the static class variable You can directly access the age variable using Class name
>>ClassTester.age=20
>>ClassTester.age
>>20
Static class variables in Python
Upvotes: 1
Reputation: 967
You are doing it wrong,
you define msg
var as an attribute to the class, and it has been evaluated once, (when you instance the class) and no more change,
so when you call:
print(Tester.msg)
you are getting the first value,
what actully is nearest to your work is just make msg
into method, simply:
class ClassTester:
age = 10
seconds = self.age * 365 * 24 * 60 * 60
msg = "You have lived for " + str(seconds) + " seconds."
def get_msg(self):
seconds = self.age * 365 * 24 * 60 * 60
self.msg = "You have lived for " + str(seconds) + " seconds."
Tester = ClassTester()
Tester.age = 20
Tester.get_msg()
print(Tester.msg)
Upvotes: 0