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.
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.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With