Scope (?) question

P

Peter

I am puzzled by what appears to be a scope issue - obviously I have
something wrong :)

Why does this work:

if __name__ == 'main':
execfile('test-data.py')
print data

and yet this doesn't (I get "NameError: global name 'data' not
defined"):

def X():
execfile('test-data.py')
print data

where test-data.py is:

data = [1,2,3,4]

I checked help on execfile and could only find the following
(mystifying) sentence:

"execfile() cannot be used reliably to modify a function’s locals."

Thanks
Peter
 
M

MRAB

Peter said:
I am puzzled by what appears to be a scope issue - obviously I have
something wrong :)

Why does this work:

if __name__ == 'main':
execfile('test-data.py')
print data

and yet this doesn't (I get "NameError: global name 'data' not
defined"):

def X():
execfile('test-data.py')
print data

where test-data.py is:

data = [1,2,3,4]

I checked help on execfile and could only find the following
(mystifying) sentence:

"execfile() cannot be used reliably to modify a function’s locals."
In the first example 'execfile' is passed globals() by default, which
'test-data.py' modifies.

In the second example 'execfile' is passed locals() by default (because
it's called from within a function), which 'test-data.py' modifies.

However, Python (well, CPython at least), optimises access to locals
within functions, which unfortunately means that changes to locals()
won't actually affect the function's locals.

Here's an example which tries to change the locals:
.... x = 0
.... print "Old value of x:", x
.... locals()["x"] = 1
.... print "New value of x:", x
....Old value of x: 0
New value of x: 0


Compare this with changing globals:
>>> x = 0
>>> print "Old value of x:", x Old value of x: 0
>>> globals()["x"] = 1
>>> print "New value of x:", x
New value of x: 1
 
I

Inyeol Lee

I am puzzled by what appears to be a scope issue - obviously I have
something wrong :)

Why does this work:

if __name__ == 'main':
  execfile('test-data.py')
  print data

and yet this doesn't (I get "NameError: global name 'data' not
defined"):

def X():
  execfile('test-data.py')
  print data

where test-data.py is:

data = [1,2,3,4]

I checked help on execfile and could only find the following
(mystifying) sentence:

"execfile() cannot be used reliably to modify a function’s locals."

Thanks
Peter

This is due to CPython's static optimization of local name lookup.
Dummy 'exec' statement disables this and makes your example work:

def X():
exec "None"
execfile('test-data.py')
print data

--inyeol
 
P

Peter

This one seems to do the trick - thanks! :)

I am puzzled by what appears to be a scope issue - obviously I have
something wrong :)
Why does this work:
if __name__ == 'main':
  execfile('test-data.py')
  print data
and yet this doesn't (I get "NameError: global name 'data' not
defined"):
def X():
  execfile('test-data.py')
  print data
where test-data.py is:
data = [1,2,3,4]
I checked help on execfile and could only find the following
(mystifying) sentence:
"execfile() cannot be used reliably to modify a function’s locals."
Thanks
Peter

This is due to CPython's static optimization of local name lookup.
Dummy 'exec' statement disables this and makes your example work:

def X():
  exec "None"
  execfile('test-data.py')
  print data

--inyeol
 
P

Peter Otten

Inyeol said:
I am puzzled by what appears to be a scope issue - obviously I have
something wrong :)

Why does this work:

if __name__ == 'main':
execfile('test-data.py')
print data

and yet this doesn't (I get "NameError: global name 'data' not
defined"):

def X():
execfile('test-data.py')
print data

where test-data.py is:

data = [1,2,3,4]

I checked help on execfile and could only find the following
(mystifying) sentence:

"execfile() cannot be used reliably to modify a function’s locals."

Thanks
Peter

This is due to CPython's static optimization of local name lookup.
Dummy 'exec' statement disables this and makes your example work:

def X():
exec "None"
execfile('test-data.py')
print data

--inyeol

You may also consider the following alternative:

def f():
ns = {}
execfile('test-data.py', ns)
print ns["data"]

f()

This has the advantage that it can be automatically converted to Python 3.

Peter
 
S

Steven D'Aprano

I checked help on execfile and could only find the following
(mystifying) sentence:

"execfile() cannot be used reliably to modify a function’s locals."

What is mystifying about it? It's short and clear -- execfile cannot be
used to reliably modify a function's local variables.

The *reason* why this is so is complicated, but the fact that it is so is
plain and simple, as you already discovered.
 
S

Steven D'Aprano

"execfile() cannot be used reliably to modify a function’s locals."
[...]
This is due to CPython's static optimization of local name lookup. Dummy
'exec' statement disables this and makes your example work:

def X():
exec "None"
execfile('test-data.py')
print data


Is this documented anywhere? It looks like a nasty hack that is liable to
disappear at any time. In fact, it looks like a nasty hack which *has*
disappeared: it doesn't work in Python 3.1:

.... exec("None")
# execfile doesn't exist any longer
.... exec(open('test.py').read())
.... print(x)
....Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in f
NameError: global name 'x' is not defined


By experimentation in Python 2.5, it seems to me that it only works if
the local variable hasn't already been defined. If it has, you can't
modify it:
.... x = 1
.... exec("None")
.... execfile('test.py')
.... print x
....1


But you can use it to define new locals:
.... exec("None")
.... execfile('test.py')
.... print x
....2
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top