Loading video player…

Looking at the Local Scope

00:00 Most of us first encounter the concept of scopes with the local scope. At least I did. If you’ve ever written or even used a function, you’ve created a local scope.

00:09 So it makes sense that it’s also called the function scope because it exists at the function level. This scope keeps names and variables isolated to their functions.

00:17 They can’t be used or modified from the outside, and this keeps your functions consistent, self-contained units. The local scope contains all variables created while the function runs, whether as parameters or defined within the function body.

00:32 And every time a function is called, a new local scope is created. When the function execution ends, that local scope is discarded. So how can you inspect the contents of a local scope?

00:44 To view variables in a local scope, you can call the built-in function locals() from inside that function. It’ll return a dictionary that is a copy of the function’s namespace at that point during its execution.

00:57 Another option is from the outside, you can access the .__code__ attribute of a function. This holds a special code class used internally by Python that holds data about the code of the function.

01:09 From there, the attribute .co_varnames holds a tuple of names local to that function. For example, my_func .__code__.co_varnames.

01:23 Let’s explore these concepts further in the REPL.

01:27 Back in the REPL now. First, you’ll define a function so you have something to work with. It’ll be called square(), and it takes in one argument.

01:34 base raises base to the power of two, and prints a string describing the result. def square(base): result = base ** 2.

01:45 The double star operator applies exponentiation. print() an f-string: f"The square of {base} is {result}".

01:57 Run square(), passing in the integer value 10. Perfect. The square of 10 is 100. Now, can you access the local variables? result

02:08 you get a NameError, base, and another NameError. As you would expect, both variables can’t be accessed. Here in the top level, the names aren’t found in any of the available scopes, so Python raises a NameError on both counts.

02:25 And remember, each local scope is self-contained. You can validate this by creating a new function, cube(), that has the same behavior as the square() function.

02:34 Only it cubes its base instead of squaring it. def cube(base): result = base ** 3. print() an f-string: f"The cube of {base} is {result}".

02:54 Now try running cube() with the argument 30. The cube of 30 is 27,000. I’m just going to trust Python that that number is accurate. So what you’ve demonstrated here is that despite both functions using the same names internally, base and result, there haven’t been any name collisions.

03:11 Each function is completely isolated from each other. While we’re here, why don’t we also look at that .__code__ attribute?

03:19 cube.__code__.co_varnames,

03:25 and the result is a tuple of base and result. You can compare against square(), square.__code__.co_varnames, and yep, the same names base and result.

03:39 And to work with the locals() function, you’ll need to create a function that calls locals() within the function body. def func(arg): var = 100.

03:49 print(locals()). another = 200. Your function has three local variables: arg, var, and another. Call func() passing in 300.

04:02 The result, the locals() dictionary is printed. Because locals() is called before the variable another is defined, all you see displayed here are the names and values for var and arg, 100 and 300, respectively.

04:16 You might now be wondering if you can change the local scope directly by modifying the dictionary returned by the locals() function. Why not give it a try? Again, you need a function to work with. def func(): with no parameters this time.

04:30 Create the variable var and set it to 100. Call locals() and use bracket accessors to grab var from the dictionary it returns, then set that to 200.

04:41 Lastly, print(var). Call func() and see what happens.

04:47 var is printed and var contains the value of 100, which is its original value, meaning that despite modifying var’s value in the dictionary returned by locals(), the variable itself stayed the same.

05:00 This is because, as mentioned before, the dictionary returned by locals() is only a copy of the namespace, and that’s the reason it can’t be used to modify variables.

05:09 And that was the local scope. Next up, I hope you aren’t claustrophobic because we’re about to be squeezing into the tight quarters of the enclosing scope.

05:19 See you in the next lesson.

Become a Member to join the conversation.