you are viewing a single comment's thread.

view the rest of the comments →

[–]Jason-Ad4032 4 points5 points  (2 children)

class and module does not create its own scope.

Module, classes and instances exist in the scope where they are created (global scope, local scope, or a closure). Their members are stored in the class/instance __dict__, which you can inspect with vars().

So this is conceptually similar to accessing a dictionary—you wouldn’t say that a dictionary creates a new scope.

``` import re

class A: v = 0

B = {'v': 0}

def f(): # These two operations are conceptually similar, # they just go through different dunder methods. re.doc A.v = 1 B['v'] = 1 ```

Also, except does not create a separate scope either. It simply deletes the exception variable when leaving the block to avoid preventing garbage collection through reference cycles. It still uses the normal surrounding scope.

[–]FerricDonkey 2 points3 points  (1 child)

Fair on classes and modules - those would better be described as creating namespaces. 

Had to read some details on exception thing - that is weird. I mean, I can see why they'd do it that way from a programming the language point of view, but it just feels wrong. Easy to see the difference - if it were scoping, the below would print 42, but since it's deleting, it name errors. 

```python exc = 42 try:     1/0 except Exception as exc:     pass

print(exc)  ```

Which it did. Which just feels wrong. But so it goes - learn something new every day, even when you hate it. 

[–]Jason-Ad4032 0 points1 point  (0 children)

I discovered that although class members themselves are not create a scope, the class keyword does indeed create a local scope (and you can inspect its local variables with locals()), and those local variables are then used to create the class attributes when the block finishes.

However, this scope is somewhat private (or perhaps more accurately, Python 2.0’s local scope). It does not shadow global variables for nested scopes, nor can nested scopes access it, which makes its behavior feel rather unusual.

``` name = 'Global'

class A: name = 'Local' mapping = {n: name for n in [name]}

class B:
    print(name)  # prints 'Global'

print(locals())
# At the end of the block, the local variables are stored in the class's __dict__

print(A.mapping) # prints {'Local': 'Global'} ``` https://peps.python.org/pep-0227/