3

It seems that if I import the same Python file via the import statements from several files and change some file-scope variable in it, the reference change will not be visible to another modules while container changes will.

For example,

First example

first.py

import reader
import helper


reader.change_buf('modified')
helper.foo()

second.py

import reader


def foo():
  print(reader.BUF)

reader.py

buf = 'original'


def change_buf(buf):
  buf = buf

Output

> python first.py
original

Second example

first.py

import reader
import helper


reader.change_first_element('1')
helper.foo()

second.py

import reader


def foo():
  print(reader.BUF)

reader.py

buf = ['0', '1', '2']


def change_first_element(new_elem):
  buf[0] = new_elem

Output

> python first.py
['1', '1', '2']

Why?

FrozenHeart
  • 19,844
  • 33
  • 126
  • 242

2 Answers2

0

tl;dr Because you're doing different things with different behaviours.

  1. In your first example, you create a local variable buf in the function change_buf; in the second example, there is no such variable to access locally, so python descends the stack upwards looking for variables that fit your request, and finds one at the module level scope.
  2. Your first example uses an assignment statement, your second statement is fancy setitem notation. The behaviour is different for the two.

Explaining the behaviour in (1), This question is similar. If you want to access a global variable explicitly using an assignment statement, use the global or nonlocal keyword, as is done here

From the docs:

It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.

Note that your second example isn't an assignment statement; it is a method call to __setitem__ on the variable buf, which happens to be type list. It might make more sense looking like this

foo = [3]
def set_foo():
    foo.__setitem__(0,3)

Now you see that foo is a "free variable" being referenced, and can only be referencing the global scope element by that name. If there was any ambiguity as to which scope foo belonged to, python would not be able to handle your case.


Python's rules about scoping can be a little complex, but are unambiguous

Community
  • 1
  • 1
en_Knight
  • 5,301
  • 2
  • 26
  • 46
0

Simply because in first example you are hiding the global variable buf behind a local one (the function parameter buf), while in second example the function parameter(new_elem) does not collide. But that's not all. In first example, you define the variable buf in a function, so it is still local by default - in second example, you use it since you set buf[0]. You must declare it global

You should write reader.py that way:

buf = 'original'

def change_buf(new_val):
    global buf
    buf = new_val
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252