I am confused about the implementation of a global namespace in python . How are variable names mapped as keys to the objects they reference as values ,since namespace is implemented as a dictionary? If keys of a typical python dict are “objects” themselves, why are variables called keys if they are just references not the actual objects?
1 Answer
Python allows you to inspect the global scope with the globals()
function. Let's try it out:
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>}
We can create a new variable in scope:
x = 5
and then look at the globals dictionary again:
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>, 'x': 5}
We can see that there is a new key, x
, with the name of the variable we created and the value I assigned to it. It's the name of the variable, as a string, that is the key here.
We can use that string name as a key directly if we like:
>>> globals()["x"] = "hello"
>>> x
'hello'
You can see that the value of the x
variable has changed when I updated the value in the globals()
dictionary at the key "x"
. The language runtime understood to take that variable name and get it from the dictionary, and vice-versa. In this way, the global variables and the dictionary entries really are identified with one another.
This is a reasonable enough way of implementing variable scopes in a dynamically-typed language: you can use dictionary/map/table lookup semantics that you already have to drive your variables. JavaScript's global scopes work the same way, for example. The language, whichever one it is, just turns a read or write of a variable to an access to the scope dictionary at the key determined by the variable's name.
Python also exposes local variables the same way (using locals()
), but JavaScript doesn't. You can imagine that the interpreter always holds on to two references to dictionaries, one for global variables and one for locals, and looks up any given variable in the corresponding dictionary. This is something that the language implementation knows to do — it's not happening "within" the user-level program, so you don't have to write globals["x"] = 5
every time you want to make an assignment, you just write the variable name and it does the rest internally.
Lots of small programming language implementations follow exactly this strategy for their variables: they give each scope a dictionary (map, table, hash, ...) for all the variables in it and turn every variable access into dictionary access, and that's it. This is convenient for implementation, because you can just make a data structure from the standard library and use it the way it's meant to be used, including for creating predefined scopes, printing it out for debugging, or lots of other common tasks.
There are a lot of fine implementation details behind the scenes here. A language doesn't need to use the same implementation strategy internally as it exposes to the user, as long as the observable behaviour is the same. High-performance JavaScript implementations generally try to optimise away these kinds of lookup, for example.
For the level of understanding you're looking for, we can treat any access to a variable as translating to a lookup in a specific dictionary using the variable's name, as a string, as the key. The implementation inherently knows where to find that dictionary for the current scope, and it knows it has to treat a variable that way when it sees one.
How string lookup inside a dictionary works is also an implementation detail. You could imagine that as a big list of pairs (key, value)
and a for loop that does a linear search through the whole list to find a matching key and return the value that came with it. This has the right semantics, but it's slower than ideal, and real implementations will likely use a more efficient data structure and lookup algorithm. It doesn't matter whether the key came from a variable name, a string literal, or user input, the dictionary will work the same way regardless.
-
$\begingroup$ I want to thank you for such clear explanation. This helped me revisit my concept . I understood. Actually with so many resources all over the internet, plus considering one is a beginner, it is really hard to grasp the basics technically and then moving on to advanced topics $\endgroup$– SilahCommented Jul 7 at 9:06
-
$\begingroup$ Are there good resources online that can help me gain and strengthen my understanding about the topics relevant to how programming languages work internally ? Also , do I really need to know about this in depth to write efficient programs or does it just depend on whether I am opting to learn about the workings of interpreted languages’ implementation? $\endgroup$– SilahCommented Jul 7 at 9:12
-
3$\begingroup$ I don't think you need to understand the internals of the implementations at this point. Those can get very complicated. For any real-world efficiency question, the contribution of the language is something you determine by profiling rather than inspection, and in most cases the program body will dominate anyway (and in any case, concerns about efficiency are probably premature optimisation right now). Most users of programming languages don't have in-depth knowledge of the implementation details of the language they are using. $\endgroup$– Michael Homer ♦Commented Jul 7 at 9:28
-
-
3$\begingroup$ FWIW, in (common implementations of) Python locals are just represented as a dict of the user requests it, but not actually stored as such. In CPython, locals are an array of pointers, with variable names compiled to indices into that array. $\endgroup$ Commented Jul 7 at 11:51
globals()
to inspect it and see how it (apparently) behaves. I also don't understand what you're asking — the question seems to answer itself when it says that the variable names are mapped as keys to the objects they reference as values, but clearly that isn't what you want to know! You can edit your question. $\endgroup$