I have started learning python classes some time ago, and there is something that I do not understand when it comes to usage of self.variables inside of a class. I googled, but couldn’t find the answer. I am not a programmer, just a python hobbyist. Here is an example of a simple class, with two ways of defining it:
1)first way:
class Testclass: def __init__(self, a,b,c): self.a = a self.b = b self.c = c def firstMethod(self): self.d = self.a + 1 self.e = self.b + 2 def secondMethod(self): self.f = self.c + 3 def addMethod(self): return self.d + self.e + self.f myclass = Testclass(10,20,30) myclass.firstMethod() myclass.secondMethod() addition = myclass.addMethod()
2)second way:
class Testclass: def __init__(self, a,b,c): self.a = a self.b = b self.c = c def firstMethod(self): d = self.a + 1 e = self.b + 2 return d,e def secondMethod(self): f = self.c + 3 return f def addMethod(self, d, e, f): return d+e+f myclass = Testclass(10,20,30) d, e = myclass.firstMethod() f= myclass.secondMethod() addition = myclass.addMethod(d,e,f)
What confuses me is which of these two is valid? Is it better to always define the variables inside the methods (the variables we expect to use later) as self.variables (which would make them global inside of class) and then just call them inside some other method of that class (that would be the 1st way in upper code)? Or is it better not to define variables inside methods as self.variables, but simply as regular variables, then return at the end of the method. And then “reimport” them back into some other method as its arguments (that would be 2nd way in upper code)?
EDIT: just to make it clear, I do not want to define the self.d, self.e, self.f or d,e,f variables under the init method. I want to define them at some other methods like showed in the upper code. Sorry for not mentioning that.
Advertisement
Answer
Both are valid approaches. Which one is right completely depends on the situation.
E.g.
- Where you are ‘really’ getting the values of a, b, c from
- Do you want/need to use them multiple times
- Do you want/need to use them within other methods of the class
- What does the class represent
- Are a b and c really ‘fixed’ attributes of the class, or do they depend on external factors?
In the example you give in the comment below:
Let’s say that a,b,c depend on some outer variables (for example a = d+10, b = e+20, c = f+30, where d,e,f are supplied when instantiating a class:
myclass = Testclass("hello",d,e,f))
. Yes, let’s say I want to use a,b,c (or self.a,self.b,self.c) variables within other methods of the class too.
So in that case, the ‘right’ approach depends mainly on whether you expect a, b, c to change during the life of the class instance. For example, if you have a class where hte attributes (a,b,c) will never or rarely change, but you use the derived attribures (d,e,f) heavily, then it makes sense to calculate them once and store them. Here’s an example:
class Tiger(object): def __init__(self, num_stripes): self.num_stripes = num_stripes self.num_black_stripes = self.get_black_stripes() self.num_orange_stripes = self.get_orange_stripes() def get_black_stripes(self): return self.num_stripes / 2 def get_orange_stripes(self): return self.num_stripes / 2 big_tiger = Tiger(num_stripes=200) little_tiger = Tiger(num_stripes=30) # Now we can do logic without having to keep re-calculating values if big_tiger.num_black_stripes > little_tiger.num_orange_stripes: print "Big tiger has more black stripes than little tiger has orange"
This works well because each individual tiger has a fixed number of stripes. If we change the example to use a class for which instances will change often, then out approach changes too:
class BankAccount(object): def __init__(self, customer_name, balance): self.customer_name = customer_name self.balance = balance def get_interest(self): return self.balance / 100 my_savings = BankAccount("Tom", 500) print "I would get %d interest now" % my_savings.get_interest() # Deposit some money my_savings.balance += 100 print "I added more money, my interest changed to %d" % my_savings.get_interest()
So in this (somewhat contrived) example, a bank account balance changes frequently – therefore there is no value in storing interest in a self.interest variable – every time balance changes, the interest amount will change too. Therefore it makes sense to calculate it every time we need to use it.
There are a number of more complex approaches you can take to get some benefit from both of these. For example, you can make your program ‘know’ that interest is linked to balance and then it will temporarily remember the interest value until the balance changes (this is a form of caching – we use more memory but save some CPU/computation).
Unrelated to original question
A note about how you declare your classes. If you’re using Python 2, it’s good practice to make your own classes inherit from python’s built in object class:
class Testclass(object): def __init__(self, printHello):
Ref NewClassVsClassicClass – Python Wiki: Python 3 uses there new-style classes by default, so you don’t need to explicitly inherit from object if using py3.