user3720101
user3720101

Reputation: 1495

Why does the same statement print two different values?

As I'm tying to understand the python self concept, I came across this example that I thought was helpful. But there is one part that confuses me. Why does print a.i output two different values? In the first case the output is 5 which makes sense to me. But then a few lines later the same print a.i statement outputs 123.

def say_hi():
    return 'hi!'

i = 789

class MyClass(object):

    i = 5

    def prepare(self):
        i = 10
        self.i = 123
        print i

    def say_hi(self):
        return 'Hi there!'

    def say_something(self):
        print say_hi()

    def say_something_else(self):
        print self.say_hi()

Output

>>> print say_hi()
hi!
>>> print i
789
>>> a = MyClass()
>>> a.say_something()
hi!
>>> a.say_something_else()
Hi there!
>>> print a.i
5
>>> a.prepare()
10
>>> print i
789
>>> print a.i
123

Upvotes: 3

Views: 129

Answers (3)

You are using global, local and instance attributes with the same name:

def say_hi():        # This is the global function 'say_hi'
    return 'hi!'    

i = 789              # This is the global 'i'

class MyClass(object):

    i = 5  # This is a class attribute 'i'

    def prepare(self):
        i = 10           # Here, you are creating a new 'i' (local to this function)
        self.i = 123     # Here, you are changing the instance attribute 'i'
        print i          # Here, you are printing the new'ed 'i' (now with value 10)

    def say_hi(self):         # This is the object method 'say_hi' function
        return 'Hi there!'

    def say_something(self):
        print say_hi()         # Here, you are calling the global 'say_hi' function

    def say_something_else(self):
        print self.say_hi()    # Here, you are calling the object method 'say_hi' function

So the ouput is correct:

>>> print say_hi()          # global
hi!
>>> print i                 # global
789
>>> a = MyClass()
>>> a.say_something()       # say_something calls the global version
hi!
>>> a.say_something_else()  # say_something_else calls the object version
Hi there!
>>> print a.i               # class attribute 'i'
5
>>> a.prepare()             # prints the local 'i' and change the class attribute 'i'
10
>>> print i                 # global 'i' is not changed at all
789
>>> print a.i               # class attribute 'i' changed to 123 by a.prepare()
123

Upvotes: 5

falsetru
falsetru

Reputation: 369424

Before the following statement in prepare method:

self.i = 123

self.i references a class attribute MyClass.i (because the instance attribute is not set)

Once the self.i = .. statement is executed, self.i reference a new value 123. (This does not affect the class attribute MyClass.i, making a new instance attribute)

Upvotes: 4

tabchas
tabchas

Reputation: 1402

You are changing the class variable i to 123 in the prepare() function:

    self.i = 123

After which you are calling the class variable by doing print a.i which will print 123 as a result.

Upvotes: 2

Related Questions