People really like to organize their code into self-contained logical blocks. If you subscribe to Clean Code, you’ll use functions to achieve something like this:
def my_task(data):
section_a = part_a(data)
section_b = part_b(data, section_a)
section_c = part_c(section_b)
result = some_more_computation(data, section_c)
return result
Pros of doing this over having the code of all called functions in my_task
directly:
- you can assign blocks of code a meaningful name
- you cleanly separate code blocks from each other
- you can re-use variable names in different functions without causing unexpected behavior
Cons:
- you have to jump around in the file if you actually want to read all of the code, making it less readable
- you create a bunch of functions on the top-level, polluting it for anyone inspecting the module, or trying to import from it
- you’re abusing functions to effectively just create a scope, which is something that functions definitely do, but more as a detail than its purpose
I’m only listing points here that relate to readability and organization. Enabling code re-usage or creating testable units are very good reasons to turn blocks of code into functions, but those cases are explicitly not what I’m trying to address here.
I’d also like to organize my code, optimally keeping all the pros and avoiding all the cons I’ve listed. A way that I feel would allow me to express this intent in a clear manner would be something very similar to SimpleNamespace
from the typing
module, but without using the class
-keyword.
That might sound like a minor thing, but as a matter of fact, SimpleNamespace
is used very rarely. I’ve honestly never seen it used in “real” code during my whole career, and I think it’s because, again, we’d be abusing something with a very specific and different purpose. And classes in particular can have wild side-effects with respect to the code defined in its body, so it’s only natural to shy away from it, even if it probably works just fine most of the time.
What I had in mind:
>>> scope foo:
... bar = "bar"
...
>>> foo.bar
bar
>>> bar
NameError: name 'bar' is not defined
I don’t care that much about the details, maybe namespace is a better keyword, or maybe it would be nice to go just foo:\n
. Maybe something like export bar
to leak a name into the surrounding scope would be better than foo.bar
-like access, who knows. I do think indenting the scoped code makes a lot of sense though.