Breaking Down the Built-in Scope
00:00
Time to talk about the built-in scope. When you examined the global scope in previous lessons, were you surprised not to see names like len
, print
or float
? Python built-ins that seem pretty global but are not actually in the global scope?
00:13
Well, that’s because they’re in the built-in scope. The built-in scope is based on the standard library module builtins
. It’s how you can use these names that are in the builtins
module without having to import them, and you can find them stored in the global scope under the special name __builtins__
.
00:30 Now let’s look at some ways you can work with the built-in scope.
00:35
Start by calling up our old friend dir()
.
00:38
And the second item in your list of names in the global scope is __builtins__
. Go ahead and pass that variable into dir()
. The result is going to be a pretty long list, including exceptions, types, functions, and other Python built-in objects.
00:52 So I’ll be using a slice to view only the last 10 elements.
00:56
dir(__builtins__)
and using bracket accessors: [-10:]
. No doubt you’ll recognize some built-in names that you’ve used before. You can get the total number of elements in builtins
using a built-in, a len()
function.
01:17
Wow, 160. You might see a different number yourself if you’re on a different version of Python. For reference, I’m on 3.13. You can also import builtins
as a module: import builtins
.
01:30
And to confirm it’s the same as __builtins__
, you can compare with the identity operator.
01:37
__builtins__ is builtins
and it returns True
, meaning they are in fact the same object. Any of the built-in functions you’re used to can be used by accessing the imported builtins
module as well.
01:50
For example, the absolute value function, abs()
: calling builtins.abs()
and passing it -42
returns 42
. Calling abs()
from the built-in scope and passing it -42
also returns 42
.
02:06
I can hear you asking, how useful is this? It looks like you’re just trying to trick me into typing more. Alright, example time. What if you redefined abs
as a global variable?
02:15
And since summer is coming up, I’ll redefine abs
to 6
. abs = 6
. Because the built-in scope is the last scope to be checked by Python during name resolution, and you just created this variable in the global scope, the built-in actually becomes inaccessible by its name, and this is something called shadowing.
02:36
So if you try to call this new abs
variable again and pass it -42
, you get a TypeError: 'int' object is not callable
because the number 6
is not a function.
02:48
However, builtins.abs()
remains unaffected. All we’ve done is add a name to the global scope. So calling builtins.abs()
, and passing in -42
returns 42
like usual.
03:02
Another recourse would be to use the del
keyword to remove the global version of abs
entirely, del abs
. Now when Python resolves the name abs
, it will search through the global scope, not find anything, and then find abs
in the built-in scope.
03:17
So abs(-42)
, returns 42
and all was well. Truth be told, this is mainly useful if you’re in an interactive Python session like the REPL here or a Jupyter Notebook, and you somehow accidentally shadow a built-in.
03:34 In practice, your best bet is to try to avoid using any built-in names for your own variables. It’s another potential source of tricky bugs, and it would also confuse other Python programmers reading your code.
03:47 And that’s all I have to say about the built-in scope. But wait, the course isn’t over yet. In the next lesson, you’ll look at closure functions and how they’re a special case of the enclosing scope.
Become a Member to join the conversation.