Suppose I wrote a function that returns a function:
def my_func(word):
def say():
print(word)
return say
f = my_func("Hello!")
print(f)
<function my_func.<locals>.say at 0x7f39fb454840>
What is the meaning of <locals> here?
Locals and globals are symbol tables. When you run a python script, a list of all local identifiers i.e. symbols with scope limited to the current block (For e.g. a function) is maintained by the interpreter. This is what <locals> refers to in your output. Similarly, there is a list of all global identifiers called globals.
You can call locals() and globals() at any point in your code to get the corresponding symbol tables in a dictionary format
Related
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
This question already has answers here:
What's the scope of a variable initialized in an if statement?
(7 answers)
Closed 3 years ago.
Can someone tell me where I can find some information about the life of variables in if statement?
In this code:
if 2 < 3:
a = 3
else:
b = 1
print(a)
It prints the variable a. But it seems to me a local variable of the if statement. In C infacts it gives me an error if I create the a variable in the if statement.
I think that this behaviour is because Python is an interpreted language. Am I right?
Python variables are scoped to the innermost function, class, or module in which they're assigned. Control blocks like if and while blocks don't count, so a variable assigned inside an if is still scoped to a function, class, or module. However Implicit functions defined by a generator expression or list/set/dict comprehension do count, as do lambda expressions. You can't stuff an assignment statement into any of those, but lambda parameters and for clause targets are implicit assignment.
Taking into consideration your example:
if 2 < 3:
a = 3
else:
b = 1
print(a)
Note that a isn't declared or initialized before the condition unlike C or Java, In other words, Python does not have block-level scopes. You can get more information about it here
Interpretation and compilation have nothing to do with it, and being interpreted is not a property of languages but of implementations.
You could compile Python and interpret C and get exactly the same result.
In Python, you don't need to declare variables and assigning to a variable that doesn't exist creates it.
With a different condition – if 3 < 2:, for instance – your Python code produces an error.
An if statement does not define a scope as it is not a class, module or a function --the only structures in Python that define a scope. Python Scopes and Namespaces
So a variable defined in an if statement is in the tightest outer scope of that if.
See:
What's the scope of a variable initialized in an if statement?
Python variables are scoped to the innermost function, class, or
module in which they're assigned. Control blocks like if and while
blocks don't count, so a variable assigned inside an if is still
scoped to a function, class, or module.
This also applies to for loops which is completely unlike C/C++; a variable created inside the for loop will also be visible to the enclosing function/class/module. Even more curiously, this doesn't apply to variables created inside list comprehensions, which are like self-contained functions, i.e.:
mylist = [zed for zed in range(10)]
In this case, zed is not visible to the enclosing scope! It's all consistent, just a bit different from some other languages. Designer's choice, I guess.
The way c language and its compiler is written is that during compile time itself "declaration of certain identifiers are caught", i.e this kind of grammar is not allowed. you can call it a feature/limitation.
Python - https://www.python.org/dev/peps/pep-0330/
The Python Virtual Machine executes Python programs that have been compiled from the Python language into a bytecode representation.
However, python(is compiled and interpreted, not just interpreted) is flexible i.e you can create and assign values to variables and access them globally, locally and nonlocally(https://docs.python.org/3/reference/simple_stmts.html#grammar-token-nonlocal-stmt), there are many verities you can cook up during your program creation and the compiler allows it as this is the feature of the language itself.
coming to scope and life of variables , see the following description, it might be helpful
When you define a variable at the beginning of your program, it will be a global variable. This means it is accessible from anywhere in your script, including from within a function.
example:-
Program#1
a=1
if2<3
print a
this prints a declared outside.
however, in the below example a is defined globally as 5, but it's defined again as 3, within a function. If you print the value of a from within the function, the value that was defined locally will be printed. If you print a outside of the function, its globally defined value will be printed. The a defined in function() is literally sealed off from the outside world. It can only be accessed locally, from within the same function. So the two a's are different, depending on where you access them from.
Program#2
a = 1
def random1():
a = 3
print(a)
function()
print(a)
Here, you see 3 and 5 as output.
**The scope of a variable refers to the places that you can see or access a variable.
CASE 1:If you define a variable at the top level of your script or module or notebook, this is a global variable:**
>>> global_var = 3
>>> def my_first_func():
... # my_func can 'see' the global variable
... print('I see "global_var" = ', global_var, ' from "my_first_func"')
output:
my_first_func()
I see "global_var" = 3 from "my_first_func"
CASE 2:Variables defined inside a function or class, are not global. Only the function or class can see the variable:
>>> def my_second_func():
... local_var = 10
... print('I see "local_var" = ', local_var, 'from "my_second_func"')
Output:
my_second_func()
I see "local_var" = 10 from "my_second_func"
CASE 3:But here, down in the top (global) level of the notebook, we can’t see that local variable:
Output:
>>> local_var
Traceback (most recent call last):
...
NameError: name 'local_var' is not defined
Assume that we have a string
function_string = 'def main():\n\treturn(1)'
How can this be compiled as a function during runtime and then be executed?
This is my current attempt, unfortunately it raises a NameError expressing that main is not defined:
self.run():
exec(self.formatted_function_string) # similar to 'function_string' in the example
print(main())
As I said in the comments, executing / evaluating arbitrary strings is a security risk. But if you really want to do this, you need to pass exec an appropriate globals dict. The natural choice here is to pass it the globals() dict, so that whatever names your exec defines get put into the global namespace.
def test(argstring):
exec(argstring, globals())
print(main())
function_string = 'def main():\n\treturn(1)'
test(function_string)
print(main)
typical output
1
<function main at 0xb7196cd4>
I am confused about the scope of python variables. How is this working
Consider the following example
i = 12
if i==12 :
str = "is equal"
else:
str = "NOT"
print str //Prints is equal - recognized the string str
The variable str is only in the scope of if statement and its scope is lost at the else statement. Since there is no hoisting in python. I am confused how this example works.I read this post and it states that Variables are scoped in the Following order
1-L (local variables are given preference)
2-E (Enclosing variables)
3-G (Global variables)
4-B (Builtin)
My question is what is the difference between Enclosing variable and local variable ?
The variable str is only in the scope of if statement and its scope is lost at the else statement.
Nope. Python is function scoped, not block scoped. Entering an if block doesn't create a new scope, so the str variable is still in scope for the print.
Enclosing variables are variables from functions enclosing a given function. They occur when you have closures:
def f():
x = 3
def g():
print x # enclosing variable
g()
Python doesn't have general block scope for, only function scope (with some additional weirdness for cases like class declarations). Any name assigned within a function will remain valid for the life of the function.
Enclosing scope applies when nesting function declarations, e.g.:
def foo(a):
def bar(b):
return a + b
return bar
So in this case, foo(1)(2) will create a bar whose enclosing scope is a foo call with a == 1, then call bar(2), which will see a as 1.
Enclosing scope also applies to lambda functions; they can read variables available in the scope surrounding the point where lambda was used, so for something like this:
val_to_key = {...} # Some dictionary mapping values to sort key values
mylist.sort(key=lambda x: val_to_key[x])
val_to_key is available; it wouldn't be in scope inside the sort function, but the lambda function binds the enclosing scope at declaration time and can therefore use val_to_key.
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], {}, {})