Reputation: 320
It is a python script tshi3.py
:
import csv
def li2ho2():
print(csv)
li2ho2()
I copied this code and pasted it in python manage.py shell
.
It works.
But I ran python manage.py shell < tshi3.py
.
Got NameError: name 'csv' is not defined
.
Why?
Enviroment:
Linux Mint 18.1
Python 3.4.1 (default, Sep 3 2014, 08:45:22)
Django==1.11.4
There is a similar question.
Upvotes: 2
Views: 1045
Reputation: 81
As said here - manage.py shell command splits globals() and locals(). So, if you need expected behaviour of variables visibility, you should update list of global variables manually with your new imported local variables. Way below is more easily than changing of manage.py shell function:
import csv
globals().update(locals())
def li2ho2():
print(csv)
li2ho2()
Upvotes: 5
Reputation: 306
I have taken a look at the code of shell
command. Here it is:
if sys.platform != 'win32' and select.select([sys.stdin], [], [], 0)[0]:
exec(sys.stdin.read())
return
The problem comes from the exec command is called without passing the globals
and locals
parameters, then by default, the globals()
and locals()
dictionary of the current scope will be used.
Remember that at module level, globals and locals are the same dictionary, but at the current scope (at django.core.management.commands.shell.Command.handle), globals() and locals() are two different dictionary. And now things become uncontrollable when the code of tshi3.py
is executed.
Let's go through each line of code:
import csv
This will import the module csv
and put it into the locals()
dictionary. So, if the locals()
dict is the same as the globals()
dict, this will also be in the globals()
dict. BUT, in our case, csv
is ONLY in the locals()
dict, NOT in the globals()
dict.
Next:
def li2ho2():
print(csv)
When the command print(csv)
is called, csv
will be looked up in the locals()
dictionary of the function li2ho2
, and it's surely not there, so csv
is looked up in the globals()
dictionary. But as what I wrote above, csv
is not in globals()
dictionary, that's why the error: NameError: name 'csv' is not defined
is raised.
I try changing the code of tshi3.py as below:
import csv
print('globals() equals to locals(): {}'.format(globals() == locals()))
print('csv is in globals(): {}'.format('csv' in globals()))
print('csv is in locals(): {}'.format('csv' in locals()))
def li2ho2():
print('inside li2ho2 function:')
print(' csv is in globals(): {}'.format('csv' in globals()))
print(' csv is in locals(): {}'.format('csv' in locals()))
li2ho2()
And run it in two different ways:
$ python tshi3.py
globals() equals to locals(): True
csv is in globals(): True
csv is in locals(): True
inside li2ho2 function:
csv is in globals(): True
csv is in locals(): False
$ ./manage.py shell < tshi3.py
globals() equals to locals(): False
csv is in globals(): False
csv is in locals(): True
inside li2ho2 function:
csv is in globals(): False
csv is in locals(): False
So, you can see it's exactly as what I explained above. This problem can be fixed by passing an empty dictionary as globals
parameters for the exec
command as below:
exec(sys.stdin.read(), {})
Hope this helps you and I am sorry for not be able to explain the problem shorter.
Upvotes: 6