views:

166

answers:

3

I'm teaching my self 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 of this?

I found related questions, but I don't really know if they are about the same

A: 

All instance variables should be called using self

Danilo
that's an unfortunate start to an SO 'career' :)
KevinDTimm
to add though, I think your answer may have been correct, just so vague (and incomplete) as to require a downvote
KevinDTimm
+8  A: 

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
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
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
@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
@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
@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
@Felix, it is, complements nicely this question thanks.
OscarRyz
+1  A: 

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
Make sense, except there is no explicit global ( or is it? )
OscarRyz
There is a global keyword, which you can use to declare a variable inside a function to be of global scope: http://docs.python.org/release/2.5.2/ref/global.html
Eli Courtwright