Execute Program

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 even globals are 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, sum is a built-in function, so it's in __builtins__. But if we define our own custom_sum function, it goes into globals.

  • >
    def custom_sum(values):
    sum = 0
    for value in values:
    sum += value
    return 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)Pass Icon
  • >
    (sum in globals().values(), sum in __builtins__.values())
    Result:
    (False, True)Pass Icon
  • Values in globals and __builtins__ are both accessible globally, so why have this distinction at all? Why doesn't sum live in globals?

  • 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 custom assert_raises function 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 sum function is inside of __builtins__, why are we able to access it by simply calling sum(...)?

  • >
    sum([1, 2, 3])
    Result:
    6Pass Icon
  • The answer is that Python automatically checks __builtins__ whenever we reference a global variable. When resolving a variable reference, Python checks globals first, then checks __builtins__. For example, if we define a sum function, 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-in sum function by accessing __builtins__["sum"]. To make sure that our sum function 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'Pass Icon
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    sum is __builtins__["sum"]
    Result:
    FalsePass Icon
  • In practice, it's a very bad idea to redefine built-ins like this! Other programmers will assume that sum refers to the familiar built-in sum function.

  • 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-in str.

  • Any code that references str now gets our string variable, not the built-in str function. When we call str(...), we're "calling" our string, which doesn't make sense and raises an exception.

  • >
    str(1)
    Result:
    '1'Pass Icon
  • >
    str = "Amir"
    str(1)
    Result:
    TypeError: 'str' object is not callablePass Icon
  • One final question: where does __builtins__ live? An earlier example hinted at it: it's in globals!

  • >
    "__builtins__" in globals().keys()
    Result:
    TruePass Icon