No, there is no language support for creating block scope.
The following constructs create scope:
- module
- class
- function (incl. lambda)
- generator expression
- comprehensions (dict, set, list (in Python 3))
No, there is no language support for creating block scope.
The following constructs create scope:
- module
- class
- function (incl. lambda)
- generator expression
- comprehensions (dict, set, list (in Python 3))
The idiomatic way in Python is to keep your functions short. If you think you need this, refactor your code! :)
Python creates a new scope for each module, class, function, generator expression, dict comprehension, set comprehension and in Python 3.x also for each list comprehension. Apart from these, there are no nested scopes inside of functions.
Why does python lack nested scopes? (a la blocks in C, or scheme's "let" statements)
Prior to 2.1 or so, you couldn't even do that -- names were looked up in the function's local scope, in the module namespace, and then in the builtin function list, and that was all. So for instance a recursive inner function like this:
def f():
def g(x):
...
g(x-1)would throw an exception due to not being able to look up 'g', as the local scope of f was never searched. There is still a wart in Python 2 when it comes to assigning to variables outside the local scope but not all the way up in the module; Python 3 adds the 'nonlocal' keyword which is similar to 'global' but for intermediate scopes.
In other words, it's a historical artifact.
In general I think the implication of this is that if you are using nested functions enough to keep running into scoping issues, the Pythonic thing to do would be to use some other construct, like a class or module, to organize that part of your code.
More on reddit.comPackage to simulate block scopes in Python
A function also creates a scope and is usually the easier and cleaner way. What is the advantage of the scoping package?
More on reddit.comcreate block scope in Python
Python Block Scopes - Someone explain this - Stack Overflow
In python, there is no non-ugly way to create a nested scope inside a function other than defining another function and then calling it.
I have to assume this is intentional. Is this python's way of hinting that functions should be short enough that you don't desire nested scopes?
Prior to 2.1 or so, you couldn't even do that -- names were looked up in the function's local scope, in the module namespace, and then in the builtin function list, and that was all. So for instance a recursive inner function like this:
def f():
def g(x):
...
g(x-1)
would throw an exception due to not being able to look up 'g', as the local scope of f was never searched. There is still a wart in Python 2 when it comes to assigning to variables outside the local scope but not all the way up in the module; Python 3 adds the 'nonlocal' keyword which is similar to 'global' but for intermediate scopes.
In other words, it's a historical artifact.
In general I think the implication of this is that if you are using nested functions enough to keep running into scoping issues, the Pythonic thing to do would be to use some other construct, like a class or module, to organize that part of your code.
I would imagine it's due in part to three things:
-
Python's "we're all adults here" attitude. Just like there's no form of access modifiers on classes or methods to prevent access to private data, there's no way to define your own scope since it effectively creates "private local variables" within that scope.
-
The only time I've needed to explicitly create my own scope in C# is in switch/case blocks where I tried to define the same variable name within two of the case blocks. Python doesn't have separate declaration from initialization, so you wouldn't run into issues just setting the variable twice.
-
In most cases, reusing the same variable name in such a way that requires custom scopes is probably a bad design.
Python's scoping rule is cleverly different from what we see in most programming languages, with which we can code things like
if flag:
result = 1
else:
result = 2without initialization. But sometimes you would still miss the mainstream behavior.
In addition to readability and code organization (where your mileage may vary), block scoping in particular helps to have variables garbage collected as soon as possible, which is useful for situations where variables may refer to expensive resources (e.g. GPU arrays).
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)https://github.com/l74d/scoping
https://pypi.org/project/scoping/
A function also creates a scope and is usually the easier and cleaner way. What is the advantage of the scoping package?
In the rare cases where I’ve had data-structures a few GB I just del’d the structure and called the built in gc.collect() module.
By no means am I shitting on your project, I’ll keep it stared incase I need easy scoping.
Hi,
does anyone know how to create block scope in Python?
In Java/C/C++, you can do the following:
{
int a = 3, b = 4;
int c = a + b
}
{
int a = 5, b = 9;
int c = a + b
}There is no inner i or outer i in this code, there is a single i variable which is assigned in two different loops.
Why should the loop break after the first iteration? Python's for is basically a for each loop in other languages, it iterates on the members of the iterator or generator given. the range function returns the list of elements [0,1,2,3,4], and each iteration i is given the next value from the list, the current value of i doesn't matter to the outer loop.
This is why the first Outer I prints the i value you expect but the second one (after the inner loop) does not.
You're reusing the i variable in your inner loop:
for i in range(5)
so you see:
Outer I Again: 4
if you change it to a different variable name then it works as expected:
In [12]:
for i in range(3):
print( '=====')
print( 'Outer I: ', i)
print( '=====')
for j in range(2):
print( 'J', j)
for l in range(5):
print( 'Inner I', l)
print( '=====')
print( 'Outer I Again: ', i)
print( '=====')
=====
Outer I: 0
=====
J 0
Inner I 0
Inner I 1
Inner I 2
Inner I 3
Inner I 4
J 1
Inner I 0
Inner I 1
Inner I 2
Inner I 3
Inner I 4
=====
Outer I Again: 0
=====
=====
Outer I: 1
=====
J 0
Inner I 0
Inner I 1
Inner I 2
Inner I 3
Inner I 4
J 1
Inner I 0
Inner I 1
Inner I 2
Inner I 3
Inner I 4
=====
Outer I Again: 1
=====
=====
Outer I: 2
=====
J 0
Inner I 0
Inner I 1
Inner I 2
Inner I 3
Inner I 4
J 1
Inner I 0
Inner I 1
Inner I 2
Inner I 3
Inner I 4
=====
Outer I Again: 2
=====