I started playing with the idea of namespaces in Python due to the recent discussions about public/private.
It’s often useful to group related items under a name, but creating a submodule isn’t always desirable.
Python currently has two constructs that introduce a new namespace (and scope), class and def.
class is fine for grouping constants or even classes, but due to Python’s name resolution rules, not for functions.
On the other hand, functions are obviously not evaluated immediately. This can be solved with a simple decorator, but retrieving the new namespace requires either an explicit return locals() or some fragile reflection. Additionally, classes and methods defined in a function get .<locals>. in their __qualname__.
I’d like to propose a new general-purpose namespace block:
namespace consts:
X = 1
Y = 2
# Name can be omitted to create a simple lexical scope,
# useful to prevent littering the outer scope.
namespace:
global x
y = ...
z = ...
x = y + z
# y and z are undefined here
Name resolution inside a namespace is similar to functions:
namespace a:
x = 1
f: Callable[[], int]
namespace b:
a.x += 1
y = 2
nonlocal f
def f() -> int:
return a.x + y
Private namespaces:
# mod.py
namespace __internal__:
from ._private_utils import my_util
def private_func(): ...
global public_func
def public_func():
return my_util(...)
# script.py
import mod
assert mod.public_func.__qualname__ == 'mod.public_func'
# Internal names are still accessible for monkey-patching and experimentation
assert mod.__internal__.private_func.__qualname__ == 'mod.__internal__.private_func'
When used as a scope, namespace can be useful for cleaning up intermediate variables that would otherwise live forever (or until the end of a function):
namespace:
# No need to `del big_object1, big_object2`, they're refcounts will be zero
# after exiting this anonymous namespace.
big_object1 = json.loads(big_json.read_string())
big_object2 = json.loads(big_json.read_string())
global x, y
x = big_object1['x']
y = big_object2['y']