A namespace is a dictionary, mapping names (as strings) to values. When you do an assignment, like a = 1
, you're mutating a namespace. When you make a reference, like print(a)
, Python looks through a list of namespaces to try and find one with the name as a key.
A scope defines which namespaces will be looked in and in what order. The scope of any reference always starts in the local namespace, and moves outwards until it reaches the module's global namespace, before moving on to the builtins
(the namespace that references Python's predefined functions and constants, like range
and getattr
), which is the end of the line.
Imagine you have a function named inner
, nested within a global function named outer
, and inner
contains a reference to a name. Python first looks in the inner
namespace. If the name's not there, Python then looks in the outer
namespace. If that fails, Python tries the module's global
namespace, then the builtin
namespace, eventually throwing a NameError
if the name isn't found.
When we say x
is in a function's namespace, we mean it is defined there, locally within the function. When we say x
is in the function's scope, we mean x
is either in the function's namespace or in any of the outer namespaces that the function's namespace is currently nested within.
Whenever you define a function, you create a new namespace and a new scope. The namespace is the new, local hash of names. The scope is the implied chain of namespaces that starts at the new namespace, then works its way through any outer namespaces (outer scopes), up to the global namespace (the global scope), and on to the builtins.
The terms can be used almost interchangeably, but that's not because they mean the same thing; it's because they overlap a lot in what they imply.
You might look into the Reader or State monads; they can be used for sharing data between (pure, monadic) functions, without resorting to explicit parameters or the like.
There's a tutorial series on F# for fun and profit about the State monad (AKA Workflow in F# parlence). I also gave a description of it in this SO answer that appears to be fairly approachable.
There are some implementations of other monads in python that you could reference too, if you have to implement your own.
Many people (myself included) find monads challenging at first, so if you're not familiar with the concept then I'd recommend looking at some of the simpler monads like Maybe or Either, and then perhaps Reader or Writer, before tackling State. The Python implementations linked to above may make things more clear for you than what you're likely to find elsewhere online (which would probably be Haskell).
A few caveats: there is still a little overhead over just functions, since the monad is involved, and this has to be used with functions; I don't think you could do this with class methods (though I could be wrong -- I've never tried it!).
UPDATE:
The "monads in python" page/lib I linked to above actually does have a state-monad implementation; check out the code starting at ###### StateChanger Monad #########
for the definition and examples.
EDIT in response to question in comment:
Yes, that's the way you'd do it -- to be extra clear, the arguments you declare the function with should not include the environment variables, just the ones the function would need normally; the environment variables will be accessible through the monadic get
and set
functions.
A Python example using the notation given in the "monads in python" link above:
@do(StateChanger) # <-- this makes makes it a stateful computation
def my_stateful_function1(arg):
# do something with `arg` here
# then put it in the state:
yield dict_state_set(key, var_from_arg)
# I believe you can leave out `mreturn` for this
@do(StateChanger)
def my_stateful_function2(arg1, arg2):
# something with `arg1` here
# get the state chained via the monad:
state = yield get_state()
# do something else stateful:
yield my_stateful_function1(arg2)
# do something with `state` dict here
# return; you have to use `mreturn` instead of `return`:
mreturn(some_value)
To run this you'd call:
ret_val = my_stateful_function2("hello","world").run(initial_state_dict)
and your return value would be a tuple:
(return_value_of_function, final_state_dict) = ret_val
Remember to use yield
when calling other stateful functions.
Admonition: Be careful about modifying the state in your functions since the Python dictionary type is mutable. You can get and set state vars, as well as apply a (lambda) function to them; you may wish to stick with this rather than pulling the state out and mutating it willy-nilly.
Best Answer
The "kw" stands for Key Word because the dictionary that you pass in is expanded to a sequence of key-word pair arguments. As to "Why have all the asterisks in the beginning?" I ask you, why not have them?
My hypothesis as to why the * characters were chosen is that they frequently have a wildcard meaning (e.g., in regular expressions or globing). This is just guess-work though and I have nothing to document that.