When is the locals dictionary set? - python

A module holds a dictionary to keep track of itscontext, such as the names defined at some point of the execution. This dictionary can be accessed through vars(module) (or module.__dict__) if module was imported, or by a call to the locals built-in function in the module itself:
Update and return a dictionary representing the current local symbol table.
But I found myself a bit confused, when I tried accessing the locals dictionary from a function. The output of a script containing only the following is an empty dictionary:
def list_locals():
print(locals())
list_locals()
But on the other hand, if a script contains exclusively the following, the output is the expected dictionary, containing __name__, __doc__ and the other module-level variables:
print(locals())
So, when is the content of the locals dictionary set?
In addition, what does "update" mean in the definition of the locals function?

The namespace of a module is the global namespace, accessed through globals(). There is no separate locals namespace, so locals(), outside of functions, just returns the global namespace.
Only functions have a local namespace. Note that locals() is a one-way reflection of that namespace; the CPython implementation for functions is highly optimised and you can't add or alter local variables through the locals() dictionary. The dictionary returned by locals() is updated whenever the namespace has changed between calls to that function.
Note also that things like list / dict / set comprehensions, generator expressions and class bodies are in reality executed as functions too, albeit with different namespace rules. In such contexts locals() will also return the separate function local namespace.

If you call locals() more than once during the same function call, it will return the same dictionary.
>>> def f():
... d = locals()
... assert 'd' not in d
... locals()
... assert 'd' in d
... assert d is locals()
... print(d)
...
>>> f()
{'d': {...}}
"Update" in this case means that the contents of this dictionary are updated to reflect the current scope of local variables that exist, but if you kept a reference to this dictionary then that dictionary will still be used.
Notice also that the locals dictionary doesn't contain a key for 'f', even though you could have accessed it during the course of the function. In case it's not obvious, that's a global, not a local.

Related

How pass a value to a variable in python function with using exec()?

A little easy problem:
exec("a=3")
print(a)
# This will print 3
If I use this:
def func():
exec("a=3")
print(a)
func()
# NameError: name 'a' is not defined.
What happened?How could I use exec() to assign it a value in a function?
Edit:I found a question with the same trouble but still didn't solved.
why do you want to do that?
I know using exec() is bad and unsafe.But recently I try to solve a OP's problem.I met it.
Python knows several kinds of scope: module global, function local, nonlocal closures, class body. Notably, scope resolution is defined statically at byte code compile time – most importantly, whether names refer to local/nonlocal or global scope cannot be changed.
Of these scopes, only global scope is guaranteed to behave similar to a dict, and as such writeable. The local/nonlocal scope is generally not writeable, and new variables cannot be added to it.
exec will write to the global scope if locals is not passed in; globals must then explicitly be set to its default of globals().
def func():
exec("a='exec'", globals()) # access only global scope
print(a)
a = 'global'
func() # prints exec
However, once a name is local to a function, exec cannot modify it.
def func():
a = 'local' # assignment makes name local
exec("a='exec global'", globals())
exec("a='exec locals'", globals(), locals())
print(a)
a = 'global'
func() # prints local
While a dict-like representation of local/nonlocal scope exists, the interpreter is not required to honour changes to it.
locals()
Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks. Note that at the module level, locals() and globals() are the same dictionary.
Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
Even though exec does take locals as a dict, these are not treated like function locals/nonlocals. Attempts to modify the default locals (the result of locals()) are not defined.
exec()
... If globals and locals are given, they are used for the global and local variables, respectively. If provided, locals can be any mapping object. Remember that at module level, globals and locals are the same dictionary. If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.
Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. ...
execute help(exec) in your python3 REPL, you will get the following docuement:
Help on built-in function exec in module builtins:
exec(source, globals=None, locals=None, /)
Execute the given source in the context of globals and locals.
The source may be a string representing one or more Python statements
or a code object as returned by compile().
The globals must be a dictionary and locals can be any mapping,
defaulting to the current globals and locals.
If only globals is given, locals defaults to it.
so there are at least 2 options to provide the value of argument 'a':
assign a value to the variable 'a' in the module's global scope:
a = 1
def func():
exec("global a;a=3")
print(a)
pass a customized global or local context to exec:
def func():
my_context = {'a': 1}
exec("a=3", None, my_context)
print(my_context['a'])
NOTE: DONT USE eval or exec IN YOUR SERIOUS CODE UNLESS YOU KNOW WHAT YOU ARE DOING.
EDIT NOTE
the following solution(2th solution mentioned in the comments) wont work:
def func():
a = 1
exec("a=3")
print(a) # still get 1 here

Strange behavior of locals() function in nested functions

To serve as closure function, it is important for an inner functions to have access to variables defined in surrounding scopes.
But why does locals() function tell us that these variables are member of local namespace, even if they are referenced to after invokation of locals()?
I referenced to a nonlocal variable x after invocation of locals(), even after return statement. I even preceded it with keyword nonlocal.
But nothing changed.
def f():
x=0
def g():
print(locals())
return
nonlocal x
g() # prints "{'x': 0}"
x=1
g() # prints "{'x': 1}
return g
g=f()
g() # prints "{'x': 1}
Since x is referenced after (and not before) invocation of locals(), I would expect that an empty dictionary {} is printed.
But instead, the result is first {'x': 0}, and after changing within outer scope {'x': 1}.
Actually, it isn't even a local variable, since it can be modified from surrounding scope.
What is actually going on?
Local symbol table stores all information related to the local scope of the program, and is accessed in Python using locals() method. however more details can be accessed from scope

about pandasql locals() and globals() method issue

For sqldf method of pandasql package, there is a "session/environment variables", could be locals() or globals(), could anyone let me know what it is for? And any document reference when should we use locals(), and when should we use globals()?
https://github.com/yhat/pandasql/
Here is my code and wondering what things pandansql is looking for thorough locals()? And locals() means namespace inside method select_first_50?
def select_first_50(filename):
students = pandas.read_csv(filename)
students.rename(columns = lambda x: x.replace(' ', '_').lower(), inplace=True)
q = "select major, gender from studentstable limit 50"
#Execute your SQL command against the pandas frame
results = pandasql.sqldf(q.lower(), locals())
return results
locals() and globals() are python built-in functions that are used to return the corresponding namespace.
In Python , Namespace is a way to implement scope. So global namespace means global scope, so variables(names) defined there are visible throughout the module.
local namepsace is the namespace that is local to a particular function.
globals() returns a dictionary representing the current global namespace.
locals()'s return depends on where it is called, when called directly inside the script scope (not inside a particular function) it returns the same dictionary as globals() that is the global namespace. When called inside a function it returns the local namespace.
In pandasql , the second argument you need to pass is basically this namespace (dictionary) that contains the variables that you are using in the query. That is lets assume you create a DataFrame called a , and then write your query on it. Then pandasql needs to know the DataFrame that corresponds to the name a for this it needs the local/global namespace, and that is what the second argument is for.
So you need to decide what to pass in, example , if your DataFrame is only defined inside a function and does not exist in global scope, you need to pass in locals() return dictionary, If your DataFrame exists in global scope, you need to pass in result of globals() .

Why is globals() a function in Python?

Python offers the function globals() to access a dictionary of all global variables. Why is that a function and not a variable? The following works:
g = globals()
g["foo"] = "bar"
print foo # Works and outputs "bar"
What is the rationale behind hiding globals in a function? And is it better to call it only once and store a reference somewhere or should I call it each time I need it?
IMHO, this is not a duplicate of Reason for globals() in Python?, because I'm not asking why globals() exist but rather why it must be a function (instead of a variable __globals__).
Because it may depend on the Python implementation how much work it is to build that dictionary.
In CPython, globals are kept in just another mapping, and calling the globals() function returns a reference to that mapping. But other Python implementations are free to create a separate dictionary for the object, as needed, on demand.
This mirrors the locals() function, which in CPython has to create a dictionary on demand because locals are normally stored in an array (local names are translated to array access in CPython bytecode).
So you'd call globals() when you need access to the mapping of global names. Storing a reference to that mapping works in CPython, but don't count on other this in other implementations.

C Python: Running Python code within a context

The Python C API function PyEval_EvalCode let's you execute compiled Python code. I want to execute a block of Python code as if it were executing within the scope of a function, so that it has its own dictionary of local variables which don't affect the global state.
This seems easy enough to do, since PyEval_EvalCode lets you provide a Global and Local dictionary:
PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
The problem I run into has to do with how Python looks up variable names. Consider the following code, that I execute with PyEval_EvalCode:
myvar = 300
def func():
return myvar
func()
This simple code actually raises an error, because Python is unable to find the variable myvar from within func. Even though myvar is in the local dictionary in the outer scope, Python doesn't copy it into the local dictionary in the inner scope. The reason for this is as follows:
Whenever Python looks up a variable name, first it checks locals, then it checks globals, and finally it checks builtins. At module scope, locals and globals are the SAME dictionary object. So the statement x = 5 at module scope will place x in the the locals dictionary, which is also the globals dictionary. Now, a function defined at module scope which needs to lookup x won't find x within the function-scope locals, because Python doesn't copy module-scope locals into function-scope locals. But this normally isn't a problem, because it can find x in globals.
x = 5
def foo():
print(x) # This works because 'x' in globals() == True
It's only with nested functions, that Python seems to copy outer-scope locals into inner-scope locals. (It also seems to do so lazily, only if they are needed within the inner scope.)
def foo():
x = 5
def bar():
print(x) # Now 'x' in locals() == True
bar()
So the result of all this is that, when executing code at module scope, you HAVE to make sure that your global dictionary and local dictionary are the SAME object, otherwise module-scope functions won't be able to access module-scope variables.
But in my case, I don't WANT the global dictionary and local dictionary to be the same. So I need some way to tell the Python interpreter that I am executing code at function scope. Is there some way to do this? I looked at the PyCompileFlags as well as the additional arguments to PyEval_EvalCodeEx and can't find any way to do this.
Python doesn't actually copy outer-scope locals into inner-scope locals; the documentation for locals states:
Free variables are returned by locals() when it is called in function blocks, but not in class blocks.
Here "free" variables refers to variables closed over by a nested function. It's an important distinction.
The simplest fix for your situation is just to pass the same dict object as globals and locals:
code = """
myvar = 300
def func():
return myvar
func()
"""
d = {}
eval(compile(code, "<str>", "exec"), d, d)
Otherwise, you can wrap your code in a function and extract it from the compiled object:
s = 'def outer():\n ' + '\n '.join(code.strip().split('\n'))
exec(compile(s, '<str>', 'exec').co_consts[0], {}, {})

Categories

Resources