-2

I know that in Python there is no such thing as private variable, that is to say, any variable within a class can be accessed from anywhere. Does this also apply to class methods? If I have a variable within a class method, does it mean its value can also be altered from the outside?

The major problem I'm facing is I have nested loops within class. I have a simple example situation below (code 1). I have a variable i in the main code, and the class method can directly read its value. However, it seems I can't alter i's value from within the class method, which is shown in code 2. So what exactly decides the rule of variable accessibility in python? What should I do to avoid variables being overwritten without me knowing it?

Code 1


class Lol():

    j = 3

    def test(self):

        for j in range(i, 4):
            print(i, self.j)

lol = Lol()
for i in range(0, 2):
     lol.test()

The output is the following:

0 3
0 3
0 3
0 3
1 3
1 3
1 3

Code 2

class Lol():

    j = 3

    def test(self):

        i = 0


lol = Lol()
for i in range(0, 2):
    print(i)
    lol.test()
    print(i)


Output:

0
0
1
1

This means the class method cannot change the value of the variable i in the main script.

Aditya Mishra
  • 1,687
  • 2
  • 15
  • 24
  • What is your second example meant to be showing? All it's doing is printing the loop `i` twice. The `i` in `test` has no relation to the `i` within the loop. They're entirely separate. – Carcigenicate Sep 04 '19 at 17:31
  • 1
    Public/private also has nothing to do with *scope*, which is what you are struggling with here. – chepner Sep 04 '19 at 17:32
  • @Carcigenicate it's meant to show that the value of `i` within the loop cannot be altered by `test`. However in code 1, the `i` in the loop can be read within `test`. – ellamenopee Sep 04 '19 at 17:34
  • Your `test()` method isn't doing anything in the second example. You are merely printing the value of `i` twice as it is defined an element in your range iteration (ie: 0, 1, ...). – h0r53 Sep 04 '19 at 17:35
  • Whenever you call test and assign a value to `i`, that value is local to the `test` method. It has nothing to do with the `i` in your range loop. – h0r53 Sep 04 '19 at 17:36
  • @chepner good point. gonna search for it right now. Thanks :) – ellamenopee Sep 04 '19 at 17:36
  • If you do need to alter the value of a variable that is outside of the scope of a class method, you can do so. You would need to do so by either using a global variable or by passing `test` a mutable type (for python: lists, sets, dictionaries). If you have a more practical use case then solutions can be provided. – h0r53 Sep 04 '19 at 17:39
  • 1
    If you search in your browser for "Python variable scope", you'll find references that can explain this much better than we can manage here. Look up the `global` keyword if you want to change the value of `i` in the main program ... and then use a proper method (global variables are rarely the right way to do things). – Prune Sep 04 '19 at 17:40
  • For an explanation of how Python's scoping works, see the accepted answer to [Short description of the scoping rules?](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) You can change non-local variables in a function or method by declaring them `global`. – martineau Sep 04 '19 at 18:07
  • You mixed up global variables, local variables and class attributes. You first have to know which is which in context of Python scopes. Then decide what to do. Also, you have to learn how a variable of a for loop works (for something in something_else:). Python is a high-level programming language and it does not behave as C or C++. – Dalen Sep 04 '19 at 21:37

1 Answers1

2

In your first example

class Lol():

    j = 3

    def test(self):

        for j in range(i, 4):
            print(i, self.j)

lol = Lol()
for i in range(0, 2):
     lol.test()

The loop in Lol.test defines a local variable j that has nothing to do with the class attribute Lol.j. i is a free variable in Lol.test, so the lookup algorithm looks in the enclosing static scope, which is the global scope in this case, for the value of i, which is provided by the for loop that calls lol.test().

(As a side note, a class statement does not create a new lexical scope that its methods can see; if you added another class attribute named i to Lol, you'll note that i inside Lol.test still looks to the scope in which Lol is defined for the value of i.)


In your second example

class Lol():

    j = 3

    def test(self):
        i = 0


lol = Lol()
for i in range(0, 2):
    print(i)
    lol.test()
    print(i)

Lol.test again creates a local variable i that has nothing to so with the value of i that your loop assigns to (and is used by the two print statements).

chepner
  • 497,756
  • 71
  • 530
  • 681