Python classes self.variables
Asked Answered
A

3

9

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.

Aynat answered 29/8, 2014 at 1:46 Comment(6)
If your methods don't (or don't need to) access any instance variables, then they don't need to be - and probably don't belong - in a class at all.Guest
Thank you for the reply Paul. Could you provide a small example? I didn't understand you. I apologize for that.Aynat
Objects in the OOP sense are conglomerates of data (instance variables) and behavior (methods). A sort method on a list class makes sense, because the elements in the list (the data) are being sorted (the behavior). A method in a list class which adds two numbers you provide to it doesn't belong in that class, since it has nothing to do with the list data. It should be a standalone function. The whole point of putting a method in a class is to give it access to a particular instance's variables. If it doesn't need that access, it should generally be a standalone function, not a method.Guest
"just to make it clear, I do not want to define the self.a, self.b, self.c or a,b,c variables under the init method. I want to define them at some other methods. Sorry for not mentioning that." -- That's bad practice. Don't do that.Entertainment
My apologies Patrick. Will try not to repeat it. Are you essentially trying to explain to me that sometimes I do not even need a class, but a simple function(s)?Aynat
@user3137724: You never need classes, in Python. You use them when they're the right tool for the job, and you don't when they're not. The temptation to stuff anything and everything into a class is one which should be avoided. Python isn't Java.Guest
C
7

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.

Cadal answered 29/8, 2014 at 1:52 Comment(11)
Thank you for the reply Tom. Have just checked that wiki.python link, but I do not understand the explanations, sorry. Yes, 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)). And 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. How does that change the situation, now?Aynat
@user3137724: If you're interested in a situation completely different to the one you put in your question, then you should really update your question to reflect the situation you're actually interested in.Guest
@user3137724 hopefully my update makes more sense to you now.Cadal
I am completely confused now. I can see you made quite an effort to explain this to me in the simplest way, but I really do not understand it. Thank you once again.Aynat
Perhaps if you can give a more concrete example of what you're trying to do (instead of a,b,c) then we can help some more. Both examples you gave are valid, each is more suited to a different real situation. You say "I do not want to define the self.a, self.b, self.c or a,b,c variables under the init method", but you don't tell us why this is - so we cannot tell you if it's right or wrong (though it probably is wrong).Cadal
There's no concrete code. I am simply puzzled by these approaches. Am I going to penalized, banned or something similar if I edit the initial code one more time(insert d,e,f variables)?Aynat
You example comes down to the object-oriented equivalent of asking "Which is better," 1 + 2 + 3, or a = 1; a + 2 + 3, or a = 1; b = 2; c = 3; a + b + c.Cadal
And I'll repeat in case you missed it: "I do not want to define the self.a, self.b, self.c or a,b,c variables under the init method", but you don't tell us why this is - so we cannot tell you if it's right or wrong (though it probably is wrong). Please tell us why you want to do that.Cadal
@user3137724: No, you won't be penalized. Improving your question is always a good thing to do.Guest
I really think this question does not relate to the question. The explained cases do not answer to the use of self. It also mixes up the variables a,b,c,d,e,f compared to the question.Abott
Sorry, should be "this answer" (not "this question") in my above comment.Abott
U
1

EDITED:

If you want to preserve the values inside the object after perform addMethod, for exmaple, if you want call addMethod again. then use the first way. If you just want to use some internal values of the class to perform the addMethod, use the second way.

Urania answered 29/8, 2014 at 1:50 Comment(2)
Thank you for the reply Levi. I do not want to define my self.a, self.b, self.c variables inside of init function. Sorry for not mentioning it. Does that change your answer?Aynat
Thank you levi. But I didn't understand you. Would you be so kind to provide a code?Aynat
G
1

You really can't draw any conclusions on this sort of question in the absence of a concrete and meaningful example, because it's going to depend on the facts and circumstances of what you're trying to do.

That being said, in your first example, firstMethod() and secondMethod() are just superfluous. They serve no purpose at all other than to compute values that addMethod() uses. Worse, to make addMethod() function, the user has to first make two inexplicable and apparently unrelated calls to firstMethod() and secondMethod(), which is unquestionably bad design. If those two methods actually did something meaningful it might make sense (but probably doesn't) but in the absence of a real example it's just bad.

You could replace the first example by:

class Testclass:
    def __init__(self, a,b,c):
        self.a = a
        self.b = b
        self.c = c

    def addMethod(self):
        return self.a + self.b + self.c + 6

myclass = Testclass(10,20,30)
addition = myclass.addMethod()

The second example is similar, except firstMethod() and secondMethod() actually do something, since they return values. If there was some reason you'd want these values separately for some reason other than passing them to addMethod(), then again, it might make sense. If there wasn't, then again you could define addMethod() as I just did, and dispense with those two additional functions altogether, and there wouldn't be any difference between the two examples.

But this is all very unsatisfactory in the absence of a concrete example. Right now all we can really say is that it's a slightly silly class.

In general, objects in the OOP sense are conglomerates of data (instance variables) and behavior (methods). If a method doesn't access instance variables - or doesn't need to - then it generally should be a standalone function, and not be in a class at all. Once in a while it will make sense to have a class or static method that doesn't access instance variables, but in general you should err towards preferring standalone functions.

Guest answered 29/8, 2014 at 3:32 Comment(6)
Thank you Paul. But what does it mean "If a method doesn't access instance variables"? Does that mean: if a method does not access instance variables created in other methods (even init)? Or does it mean if we access instance variable in some method outside of class (for example myclass.d - for accessing instance variable self.d from secondMethod() method)?Aynat
In this context it means if it does not access any variable starting with self.. It's irrelevant which method they were created in (as Patrick mentions in the comments, as a general rule you should create all instance variables in __init__() anyway). If you're accessing an instance variable from outside the class altogether, then obviously you will not use self. to do so, unless you break every naming convention out there.Guest
Thank you for the effort and replies Paul. I am still confused, but at least I have two starting points now: - if a method doesn't access instance variables then it should not be a method. - create all instance variables in init method.Aynat
To reduce your confusion, just think of it the other way round. If a method doesn't access any instance variables, why would you want to put it in the class? It's not working on any of your data, so why have it there? The purpose of creating instance variables in __init__() is two-fold: (1) __init__() is always run, and it's run before any other method is, so you remove the risk of another method attempting to access an instance variable before it's been created; and (2) if you want to know which instance variables a class creates, __init__() is the only place you need to look.Guest
"If a method doesn't access any instance variables, why would you want to put it in the class" Could it be because I want to use some method simply as block of organized, reusable code (the same as function) but inside of class? Meaning I do not want to make a class, and then a function out of that class. It's much clearer if I would insert that function into a class to organize some code. Is this just stupidity?Aynat
Organizing code in an incoherent and disorganized way is not a good approach. If you want to organize a collection of related but standalone functions in Python, you use a module, not a class. You use a class when you want class-like behavior. When you don't want class-like behavior, Python has better options.Guest

© 2022 - 2024 — McMap. All rights reserved.