2

I'm confused about the namespace and scope of variables in python

Suppose I have a test.py:

# -*- coding: utf-8 -*-
"""
@author: jason
"""

if __name__ == '__main__':
    global strName
    print strName

and then, I define a variable named strName and try to access it in the test.py, but it throws an error:

In [9]: strName = "Joe"

In [10]: run test.py hello
---------------------------------------------------------------------------  NameError                              Traceback (most recent call last)  C:\Anaconda\lib\site-packages\IPython\utils\py3compat.pyc in execfile(fname, glob, loc)
    195             else:
    196                 filename = fname
--> 197             exec compile(scripttext, filename, 'exec') in glob, loc
    198     else:
    199         def execfile(fname, *where):

d:\playground\test.py in <module>()
     13         print "hello"
     14         global strName
---> 15         print strName
     16 

NameError: global name 'strName' is not defined

In [11]:

I was wondering why this happens and is there any way to access strName in test.py?

Jason Yang
  • 554
  • 7
  • 25

3 Answers3

4

global isn't global. global is module-level; truly global variables like min and int live in the __builtin__ module (builtins in Python 3). Using a global declaration at module level is redundant.

I strongly recommend you pass your data to test.py another way, such as by defining a function in there and passing your string as an argument:

test.py:

def print_thing(thing):
    print thing

other code that wants to use test.py:

import test
test.print_thing("Joe")
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • I haven't tested, and will never test, but I believe: `globals().update({'strName' : 'Joe'})` should work. Although, this comment alone is burning my hands from the pure evil that this statement embodies, in the case that this works. – Dair Jun 06 '14 at 06:27
  • @anon: `globals` is module-level too. `import __builtin__; __builtin__.strName = "Joe"` works, although it's something to only do in case of dire necessity. – user2357112 Jun 06 '14 at 06:32
1

test.py:

strName = "John Doe"
print strName

Interactive Shell:

$ python
>>> from test import strName
>>> print strName
John Doe
James Mills
  • 18,669
  • 3
  • 49
  • 62
  • I think this misses the point as he wants the module to access `strName` from the user, *not* the other way around. – Dair Jun 06 '14 at 06:05
  • Yes I can see that -- However what the OP is trying to do clearly won't work without some magic :) – James Mills Jun 06 '14 at 06:09
  • @James Mills thanks, but but I'm still wondering what's the scope of strName if I define it by enter strName = 'Joe' in shell? and how can I access this variable within a module (except passing strName as a parameter of function)? – Jason Yang Jun 06 '14 at 06:11
  • Precisely what you said (*later part*). YOu **should** pass variables as arguments to a function. I'm not even sure that declaring ``strName`` as a global would even work in the use-case you're describing. – James Mills Jun 06 '14 at 06:12
0

Global is specifically for cases where you have a variable defined outside a method, and want to use it inside that method without passing in parameters. It is put at the top of the method so that python treats that variable as a global variable, rather then a new local variable with the same name. Global is not a way to declare variables, and since strName isn't in existance, global can't figure out where the location of strName is.

Natecat
  • 2,175
  • 1
  • 17
  • 20
  • In Python 3 this was changed to ``nonlocal`` to avoid confusion. – James Mills Jun 06 '14 at 06:01
  • @JamesMills: It wasn't. `global` is still there; `nonlocal` is specifically for referring to variables from outer but nonglobal scopes. You can see in the [language reference](https://docs.python.org/3/reference/simple_stmts.html#the-nonlocal-statement) that the definition disallows using it for global variables. – user2357112 Jun 06 '14 at 06:04