8

I'm teaching myself Python and I was translating some sample code into this

class Student(object):
    def __init__( self, name, a,b,c ):
        self.name = name
        self.a = a
        self.b = b
        self.c = c

    def average(self):
        return ( a+b+c ) / 3.0 

Which is pretty much my intended class definition.

Later in the main method I create an instance and call it a:

if __name__ == "__main__" :
    a = Student( "Oscar", 10, 10, 10 )

That's how I find out that the variable a declared in main is available to the method average and to make that method work, I have to type self.a + self.b + self.c instead.

What's the rationale for this?

TylerH
  • 20,799
  • 66
  • 75
  • 101
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • 2
    As a side note, always inherit `object` so that you are using *new-style classes*, i.e., `class Student(object):`. – Mike Graham Apr 20 '10 at 20:14
  • @Mike Subclassing `object` in Python 2.x is good practice, but in Python 3, this is unnecessary, as all classes are "new-style". I realize Python 3 adoption is poor, and assuming the OP is using Python 2.x is reasonable, but some day I hope it will be a poor assumption. – gotgenes Apr 23 '10 at 22:31

3 Answers3

10

Barenames (like a, b, c) are always scoped as local or global (save for nested functions, which are nowhere around in your code). The rationale is that adding further scopes would needlessly make things more complicated -- e.g, if in your self.a = a the barename a could be scoped to mean what you appear to want (equivalent to self.a) then the assignment itself would be meaningless (assigning a name to itself), so you'd need further complicated rules.

Just using qualified names (like self.a) when you want something different than barenames' simple, straightforward, and optimized behavior, is by far the simplest approach -- perfectly workable, no complicated rules whatsoever, and allows the compiler to optimize things effectively (since e.g. a barename's scope is always lexically determined, not dependent on dynamically varying characteristics of the environment). So, besides perhaps nostalgia for other language with more complicated scoping rules, there's really no rationale for complicating the semantics of barenames.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • I almost get it... what I don't quite get, is, what would happen if I declare a local `a` within my method... ( I guess I'll find it out by typing just a little ) BRB – OscarRyz Apr 20 '10 at 18:24
  • I'm back.. so when I declare a local variable `a` it takes precedence over the global variable `a` ( as expected ) I guess the only way I have to use that global variable is.. not naming my local the same, right? – OscarRyz Apr 20 '10 at 18:27
  • @Oscar Reyes: If you want to use such a variable, pass it as parameter to the method, e.g. `student.average(a)` where `def average(self, para)`. Than you can use `para` inside your method and it will have the value you provide when you call the method. But this is not Python specific, it's this way in any programming language... – Felix Kling Apr 20 '10 at 18:31
  • @Felix I didn't really mean to use it, I was wondering what would happen if I accidentally name a local the same as a global. It does what is expected, the local take precedence over the global :) – OscarRyz Apr 20 '10 at 18:33
  • @Oscar Reyes: Ok I just read your comment this way ;) Anyway, maybe this is also interesting for you: http://stackoverflow.com/questions/370357/python-variable-scope-question – Felix Kling Apr 20 '10 at 18:36
2

There are several reasons, though the main one is from the Zen of Python: "Explicit is better than implicit." In a language like C++, a method on the class always has an implicit argument this which is pushed onto the stack every time the method is called. In this case, when an instance variable b exists as well as a global variable b, then the user may just refer to b referring to one without realizing that the other will be used. So Python forces you to be explicit about your scope to avoid confusion.

With that being said, there are other reasons as well. For example, I may define a function outside of a class and then attach it to a class at runtime. For example:

def log(self):
    print "some library function requires all objects to have a log method"
    print "unfortunately we're using the Student class, which doesn't have one"
    print "this class is defined in a separate library, so we can't add the method"
    print "fortunately, we can just add the method dynamically at runtime"

Student.log = log

Here the fact that self is explicit makes it trivial for us to define a function outside of a class and then attach it to that class. I don't do this sort of thing incredibly often, but it's EXTREMELY useful when I do.

Here's an even more complex example; suppose we want to define a class inside another class, such as for the purposes of unit testing:

class SomeUnitTests(TestCase):
    def test_something(self):
        class SomeMockObject(SomeActualObject):
            def foo(self2):
                self.assertEqual(self2.x, SOME_CONSTANT)

        some_lib.do_something_with(SomeMockObject)

Here the presence of an explicit self (which we can call whatever we want, it doesn't have to be self) allows to to distinguish between the self of the inner and outer classes. Again, this isn't something I do frequently, but when I do then it's incredibly useful.

Eli Courtwright
  • 186,300
  • 67
  • 213
  • 256
-1

All instance variables should be called using self

Danilo
  • 79
  • 1
  • 3
  • to add though, I think your answer may have been correct, just so vague (and incomplete) as to require a downvote – KevinDTimm Apr 20 '10 at 18:36