Python in Detail: __builtins__
Welcome to the __builtins__ lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
In an earlier lesson, we saw the
__builtins__dictionary in passing.>
type(__builtins__)Result:
Values like
print,type, and evenglobalsare stored in__builtins__.>
list(__builtins__.keys())Result:
(Note that if you run Python locally on your own computer,
__builtins__might be a module instead of a dictionary. Whether it's a dictionary or a module, the idea is the same: it still contains all of the same values.)Python has a lot of built-ins, so this is a big dictionary! If you read through the list, you'll see many other familiar names:
True,False,len,str,KeyError, etc.For example,
sumis a built-in function, so it's in__builtins__. But if we define our owncustom_sumfunction, it goes intoglobals.>
def custom_sum(values):sum = 0for value in values:sum += valuereturn sum- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
(custom_sum in globals().values(), custom_sum in __builtins__.values())Result:
(True, False)
>
(sum in globals().values(), sum in __builtins__.values())Result:
(False, True)
Values in
globalsand__builtins__are both accessible globally, so why have this distinction at all? Why doesn'tsumlive inglobals?One answer is that it's just how Python is implemented. However, it also has a useful purpose. When we look at a module's
globals(), we want to see the module's contents, not 150 or so Python built-ins.>
list(globals().keys())Result:
We didn't define anything in that example, so there were only two globals:
__builtins__itself, and the customassert_raisesfunction that Execute Program uses in some examples. If you open a Python REPL (the interactive shell) and run that same code, you'll see something like this:>
# This example shows what we'd get when running this code at a Python REPL.list(globals().keys())Result:
__name__is the module's name, and__doc__is its docstring. We won't go through all of the keys, but all of them are details about the module itself, except for__builtins__. This is why__builtins__is useful: it provides a clear separation between the module's contents vs. the Python built-ins.You might wonder: if the
sumfunction is inside of__builtins__, why are we able to access it by simply callingsum(...)?>
sum([1, 2, 3])Result:
6
The answer is that Python automatically checks
__builtins__whenever we reference a global variable. When resolving a variable reference, Python checksglobalsfirst, then checks__builtins__. For example, if we define asumfunction, Python will use ours, even though the built-in one still exists inside of__builtins__.In the code below, we demonstrate that by defining our own
sum. Internally, it uses the built-insumfunction by accessing__builtins__["sum"]. To make sure that oursumfunction is actually called, we'll have it return a string rather than a number.>
def sum(numbers):return str(__builtins__["sum"](numbers))sum([1, 2, 3])Result:
'6'
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
sum is __builtins__["sum"]Result:
False
In practice, it's a very bad idea to redefine built-ins like this! Other programmers will assume that
sumrefers to the familiar built-insumfunction.However, it's also important to remember that this is possible, because we sometimes do it accidentally. For example, we might store a string in a variable named
str. That might be a fine variable name in a different language, but in Python it shadows the built-instr.Any code that references
strnow gets our string variable, not the built-instrfunction. When we callstr(...), we're "calling" our string, which doesn't make sense and raises an exception.>
str(1)Result:
'1'
>
str = "Amir"str(1)Result:
TypeError: 'str' object is not callable
One final question: where does
__builtins__live? An earlier example hinted at it: it's inglobals!>
"__builtins__" in globals().keys()Result:
True