JAM JAM - 3 months ago 8
Python Question

Accessing global variables from test file

I have a file A with 2 global variables

root = ""
crumbs = []


def read(line):
global root, crumbs

line = line.strip()
open_tag = is_valid_open(line)
kv = get_kv(line)

if open_tag is not None:
root += open_tag + "."
print root <---------- prints stuff

elif kv is not None:
crumbs.append(kv[0] + "=" + kv[1])
print crumbs <---------- prints stuff


I have a test from which I

from A import read, root, crumbs


I feed it some data

read('<a>')
read('<b>')
read('<d>acceptor</d>')


And print the results

print "." + root + "." <---------- prints NOTHING
print "." + str(crumbs) + "." <---------- prints stuff


Why do I have access to the list but not String from my test file? Seems like if one works other one should work as well.

Answer

In short, it's because += does different things for lists and strings.

  • Strings are immutable. Therefore, root += ... in your A.py creates a new string and assigns it to root. There were two references to root: one in A.py and one in your test script. The root += line changes only root in A.py since that's the only one that a function in A.py has access to. The root in your test module is not changed.

  • Lists are mutable. Therefore, crumbs += modifies the existing list, and doesn't change what crumbs points to. Since crumbs still refers to the same list in both A.py and in your test module, you see the change in your test module.

It becomes clearer if you write these statements without +=:

  • root = root + ... obviously makes a new string and changes root to point to it
  • crumbs.extend(...) obviously does not make a new list and does not change what crumbs points to

This little bit of confusion can arise when you try to access variables between modules without using fully qualified names. You end up with multiple names that initially (following the import) refer to the same object, but later something changes this.

The solution is just to import A and refer to A.root and A.crumbs in your test script. That way there is only one canonical name for those objects, and the names are "owned" by the module that changes them.

Comments