Static/Dynamically Scoped,Typed,Binding - python

I am asking this just to clarify if i am thinking right.
Statically/Dynamically typed
A language is statically typed if the type of a variable is known at compile time. This in practice means that you as the programmer must specify what type each variable is. Example: Java, C, C++.
A language is dynamically typed if the type of a variable is interpreted at runtime. This means that you as a programmer can write a little quicker because you do not have to specify type everytime. Example: Perl
Static/Dynamic Binding-which the following link clearly explains the difference
Static Binding and Dynamic Binding
The main thing that i want to ask starts from here.
I know the difference between Static Scoping and Dynamic Scoping.
However as i was going through stack overflow people said that C++ and Python are Statically Scoped.
In c++ if i type
int void main(){
cout<<i;
int i=15;
}
int i=10;
It works(even in java).However its python equivalent
def foo():
print(x)
x=10
x='global'
foo()
Gives an error.

The scope is static in Python as well as in C++. The difference between those languages is related to rules that define start and end of the scope of names.
In C++ the variable i is considered as global before the local definition int i=15;.
In Python:
What are the rules for local and global variables in Python?:
If a variable is assigned a value anywhere within the function’s body,
it’s assumed to be a local unless explicitly declared as global.
Naming and binding:
When a name is used in a code block, it is resolved using the nearest
enclosing scope.
So, since the variable x is assined inside foo() it is assumed to be a local variable starting from the beginning of the function foo().
It is possible to treat x within entire function block as global using the global keyword:
def foo():
global x # name 'x' refers to the global variable
print(x) # print global 'x'
x=10 # assign global variable
x='global'
foo() # print 'global'
foo() # print '10'
Actually it is possible to access the global variable x even if you want to have a local name x in the same function using globals() build-it function:
def foo(): # name 'x' refers to the local variable
print(globals()['x']) # access the global name 'x'
x=10 # assign local variable
print(x) # print local 'x'
x='global'
foo()

Related

Why Python "global" statement is always evaluated, even under conditional statement that is not met?

I don't know how to explain the case, just try for yourself:
x = 7
def f():
if False:
global x
print("global")
x += 1
f()
print(x)
In my opinion, the above code should result in "UnboundLocalError: local variable 'x' referenced before assignment", but instead it not only works, but it changes the global variable 'x'.
A function gets a local namespace every time it is called. Python needs a way to know which variables are defined in that namespace or a containing namespace. Instead of requiring that all local variables be declared local, python's rule is that any variable that is assigned in a function is local to that function. It figures this out at compile time.
The global keyword does the opposite. It tells python that in this single function, assignment to the "global" variable is really an assignment in the enclosing namespace. Like local variables, this is figured out when the function is compiled. Because of compilation issues, python requires that the global be declared before the first reference to the variable. This is a compile thing, not a runtime thing, so its okay for it to be in a block that isn't ever really run.

Global and local scope in python

Just a beginner question about local and global scope in python
X = 100
#is X a global variable?.We defined it outside the function scope
def foo():
print(X)
return X
#it prints 100 and even returns it
def foo():
X = X + 10
#local error
#UnboundLocalError: local variable 'X' referenced before assignment
def foo():
global X
# if X is a global variable why specify again?
X = X + 10
return X
To modify global copy of a variable you need the to use the global keyword, but you don't need global if you are only accessing that.
from the python website:
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
this means that you can access a global variable inside a function without a global keyword. if you want to change it though, you must use the global keyword beforehand.
global and nonlocal are very strange things when I was a beginner.
Just think about it: why do we need them in Python?
It is because we don't need var, let and such similar things to declare variables.
Think about Javascript, it is dynamic script language too and very alike to python, but it needs var or let or const to declare variables.
The most important thing of declaring variables is to determine scope.
So, in Python, our variables have implicit default scope: current scope where they are defined, and if we want to change scope of some variables, we need use global or nonlocal explicitly .
All names on the left side of = mean to define variables.
Before executing code of some certain scope, Python will pre-compute all local variables, which are those on the left side of =. This is why you got UnboundLocalError: local variable 'X' referenced before assignment in:
def foo():
X = X + 10
So, if we look up those names not in defined current scope, just
follow the rules of scope chain: up, up, up and until built_in.
Remember: scope of any name on the left side of = is default current scope, and you have to assign it(bind something to it) before referring it.

Local and global references with UnboundLocalError

I don't quite understand why the code
def f():
print(s)
s = "foo"
f()
runs perfectly fine but
def f():
print(s)
s = "bar"
s = "foo"
f()
gives me UnboundLocalError. I know that I can fix this by declaring s as a global variable inside the function or by simply passing s an an argument into the function.
Still I don't understand how python seemingly knows whether or not s is referenced inside the function before the line has been executed? Does python make some sort of list of all local variable references when the function is read into the global frame?
Other answers have focused on the practical aspects of this but have not actually answered the question you asked.
Yes, the Python compiler tracks which variables are assigned when it is compiling a code block (such as in a def). If a name is assigned to in a block, the compiler marks it as local.Take a look at function.__code__.co_varnames to see which variables the compiler has identified.
The nonlocal and global statements can override this.
Yes, Python will look-ahead to recover all variables declared in the local scope. These will then overshadow global variables.
So in your code:
def f():
print(s)
s = "foo"
f()
Python did not find s in the local scope, so it tries to recover it from the global scope and finds "foo".
Now in the other case the following happens:
def f():
print(s)
s = "bar
s = "foo"
f()
Python knows that s is a local variable because it did a look-ahead before runtime, but at runtime it was not assigned yet so it raised and exception.
Note that Python will even let you reference variables that have not been declared anywhere. If you do:
def foo():
return x
f()
You will get a NameError, because Python, when not finding, x as a local variable will just remember that at runtime it should look for a global variable named x and then fail if it does not exist.
So UnboundLocalError means that the variable may eventually be declared in scope but has not been yet. On the other hand NameError means that the variable will never be declared in the local scope, so Python tried to find it in the global scope, but it did not exist.

Scope of Python variables in this case - Difference between Enclosing and Local Variable

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.

Confusion about Python variable scope

I came across some code which kind of puzzled me. Here's a minimal example which shows this:
# of course, the ... are not part of the actual code
some_var = {"key1":"value1" ... "keyN":"valueN"}
def some_func():
v = some_var["key1"]
The code works, but the fact that I can access some_var directly confuses me. The last time I had to write some Python code, I remember having to write some_func like this:
def some_func():
global some_var
v = some_var["key1"]
I am using Python 2.7.1 on a Windows 7 PC. Did something change in the 2.7 release that allows for this?
No, you just can't reassign some_var in a local scope. Consider the following:
some_var = {}
def some_func():
# some_var[5] = 6
some_var = {1:2}
some_var[3] = 4
some_func()
print (repr(some_var)) # {}
You'll see the assignment in some_func actually creates a local variable which shadows the global one. Therefore, uncommenting the line would result in an UnboundLocalError - you can't access variables before they're defined.
There's a difference between using (e.g. calling or using in an expression) a name from an outer scope and assigning it (and there's a difference between assigning a bare variable and assigning a member of an object pointed to by a variable - x.y = ... and x[...] = ... count as method calls!).
You only need to declare that a variable is from an outer scope if you're re-assigning it. In Python 2, you can only do that with global variables (via global var), in Python 3 you can do it for abritarily nested scopes (e.g. closures) using nonlocal var.
Using a nonlocal variable as in you example doesn't require global. It does, however, as soon as you assign the variable (with the aforementioned definition of assignment) anywhere within that scope - so add a line some_var = ... after the line where you're using it and you'll get an UnboundLocalError. Refer to the documentation for the nitty gritty details.
You only have to use global if you want to assign a new value to that variable.
Nested scope was introduced in Python 2.1 (and enabled by default in Python 2.2) (emphasis mine):
Put simply, when a given variable name is not assigned a value within a function (by an assignment, or the def, class, or import statements), references to the variable will be looked up in the local namespace of the enclosing scope. A more detailed explanation of the rules, and a dissection of the implementation, can be found in the PEP.
You only need to use global if you intend to assign to the variable, for reading the variable this is not necessary. This difference is not arbitrary, though it may seem like it at first glance.
When reading a value the interpreter can just look for a local variable named some_var, if it cannot find it then it looks for a global variable of that name. These are simple and straight forward semantics.
When assigning values to a variable the interpreter needs to know whether you intend to assign to a local variable some_var or a global variable. The interpreter assumes that some_var = 2 when called within a function is assigning to a local variable, this makes sense since this is the most common case. For the relatively rare times when you want to assign to a global variable from within a function then you use the global modifier global some_var = 2.
It depends on the usage of the variable in the function
Python variable scope error
Assigning a value to a name makes the name local, unless the name is explicitly declared global.
a = 12
def foo():
a = 42
print a # uses local
foo()
>>> 42
def foo():
global a
a = 42
foo()
print a
>>> 42
If a name is not assigned to, it is global.
a = 12
def foo():
print a # uses global
foo()
>>> 12
In short, you only have to explicitly declare a name global if you will be assigning to it. If you are just reading from it, you can use it at will. However, if you ever assign to the variable, it will be considered local in that function unless you declared it global.
b = 5
def foo():
print b
b = 7
foo()
>>> ???
Since b is assigned to in foo() and not declared global, Python decides at compile time that b is a local name. Therefore b is a local name throughout the whole function, including at the print statement before the assignment.
Therefore the print statement gives you an error, because the local name b has not been defined!

Categories

Resources