Current Affairs updated daily
KalviGavaniKalviGavani
Class 12 · Tamil Nadu State Board

Python Scoping Exercise Solutions | KalviGavani

Complete Samacheer Kalvi Class 12 Computer Science Chapter 3 exercise solutions covering variable scope (local, global, nonlocal), the LEGB rule, namespaces, module-level scope, closures, and the global/nonlocal keywords with Python code examples.

Updated 13 June 202624 min read

Chapter 3 — Scoping: Exercise Solutions Guide

How to Use This Page

1. Attempt every exercise question on your own first — use your Samacheer Kalvi textbook and class notes. 2. Compare your answers with the solutions below only after you have written your own. 3. Read the explanations for MCQs and True/False items — understanding why an answer is correct is more important than the answer itself. 4. Practise the short and detailed answers by writing them in your own words; do not memorise verbatim. 5. Use the Exam Checklist at the end for a quick pre-exam revision round.


Key Concepts (Quick Recap)

  • Scope is the region of a program where a variable name is accessible.
  • Local scope: Variables defined inside a function; accessible only within that function.
  • Global scope: Variables defined outside all functions; accessible throughout the module.
  • Enclosing scope: Variables in the outer function of nested functions; accessible to inner functions.
  • Built-in scope: Python's predefined names like len, print, max, min, int, str.
  • The LEGB rule defines name resolution order: Local → Enclosing → Global → Built-in.
  • The global keyword allows a function to modify a global variable.
  • The nonlocal keyword allows a nested function to modify a variable from its enclosing function.
  • A namespace is a container that maps names to objects; Python has built-in, global, enclosing, and local namespaces.
  • Shadowing occurs when a local variable has the same name as a global variable; the local one takes precedence inside the function.
  • A closure is a nested function that remembers variables from its enclosing scope even after the outer function has finished.
  • Functions can access (read) variables from outer scopes, but modifying them requires global or nonlocal.

I. Choose the Best Answer (MCQs)

1. What is the output of the following code?
x = 10
def func():
    x = 20
    print(x)
func()
print(x)
Answer

(a) 20 20 (b) 10 10 (c) 20 10 (d) Error

Answer(c) 20 10 Inside func(), x = 20 creates a new local variable that shadows the global x. The print(x) inside the function prints the local x (20). The print(x) outside prints the global x (10), which was never modified.

2. Which keyword is used to modify a global variable inside a function? (a) nonlocal (b) global (c) static (d) extern

Answer(b) global The global keyword tells Python that a variable inside a function refers to the global variable, allowing it to be modified. Without global, assignment inside a function creates a local variable.

3. According to the LEGB rule, what is the order in which Python searches for a variable name? (a) Local → Global → Enclosing → Built-in (b) Global → Local → Enclosing → Built-in (c) Local → Enclosing → Global → Built-in (d) Built-in → Global → Enclosing → Local

Answer(c) Local → Enclosing → Global → Built-in LEGB stands for Local, Enclosing, Global, Built-in. Python searches for a name in this order, from the innermost scope outward.

4. What is the output of the following code?
x = 5
def outer():
    x = 10
    def inner():
        nonlocal x
        x = 20
    inner()
    print(x)
outer()
Answer

(a) 5 (b) 10 (c) 20 (d) Error

Answer(c) 20 Inside inner(), nonlocal x refers to x in the enclosing outer() function. So x = 20 modifies outer's x from 10 to 20. The print(x) inside outer() then prints 20.

5. Which of the following is a built-in name in Python? (a) my_variable (b) len (c) outer (d) x

Answer(b) len len is a built-in function in Python, part of the built-in namespace. my_variable, outer, and x are user-defined names, not built-in.

6. What happens if a local variable and a global variable have the same name? (a) Python raises an error (b) The global variable is used inside the function (c) The local variable shadows the global variable inside the function (d) Both variables are merged

Answer(c) The local variable shadows the global variable inside the function When a function defines a local variable with the same name as a global variable, the local variable takes precedence (shadows the global) inside that function. The global variable remains unchanged and accessible outside the function.

7. What is the output of the following code?
x = "global"
def outer():
    x = "enclosing"
    def inner():
        x = "local"
        print(x)
    inner()
outer()
Answer

(a) global (b) enclosing (c) local (d) Error

Answer(c) local inner() has its own local x = "local". According to LEGB, Python finds x in the Local scope first, so it prints "local" without checking Enclosing or Global scopes.

8. What is a namespace in Python? (a) A variable name (b) A container that maps names to objects (c) A Python module (d) A function definition

Answer(b) A container that maps names to objects A namespace is a system that maps names (identifiers) to objects. Python has multiple namespaces: built-in (contains len, print, etc.), global (module-level names), enclosing (outer function names), and local (current function names).

9. Which keyword is used to modify a variable from the enclosing scope in a nested function? (a) global (b) nonlocal (c) enclosing (d) outer

Answer(b) nonlocal The nonlocal keyword allows a nested function to modify a variable defined in its enclosing (outer) function. global is used for module-level variables, not enclosing-scope variables.

10. What is the output of the following code?
def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

c = counter()
print(c())
print(c())
Answer

(a) 1 1 (b) 0 1 (c) 1 2 (d) Error

Answer(c) 1 2 counter() returns the increment function, which forms a closure over count. The first c() call increments count from 0 to 1 and returns 1. The second c() call increments count from 1 to 2 and returns 2. The count variable persists between calls because of the closure.

II. Fill in the Blanks

1. The region of a program where a variable is accessible is called its scope.

2. The LEGB rule stands for Local, Enclosing, Global, Built-in.

3. A variable defined inside a function is called a local variable.

4. A variable defined outside all functions is called a global variable.

5. The global keyword is used to modify a global variable inside a function.

6. The nonlocal keyword is used to modify an enclosing-scope variable inside a nested function.

7. When a local variable has the same name as a global variable, the local variable shadows the global variable inside the function.

8. A namespace is a container that maps names to objects.

9. A function that remembers variables from its enclosing scope even after the outer function has finished is called a closure.

10. Python's built-in functions like len(), print(), and max() belong to the built-in scope.


III. True or False

1. A local variable can be accessed outside the function in which it is defined. False. A local variable exists only within the function where it is defined. Attempting to access it outside causes a NameError.

2. The global keyword is needed to read a global variable inside a function. False. Reading a global variable inside a function does not require the global keyword. The global keyword is only needed when you want to modify (assign to) a global variable.

3. The LEGB rule determines the order in which Python searches for a variable name. True. Python searches for a name in the order: Local, Enclosing, Global, Built-in (LEGB). It returns the first match found.

4. A closure can access variables from its enclosing scope even after the outer function has returned. True. A closure "remembers" the variables from its enclosing scope. When the inner function is called later, it still has access to those variables, even though the outer function has finished executing.

5. The nonlocal keyword is used to modify a global variable. False. nonlocal is used to modify a variable in the enclosing (outer) function scope. To modify a global variable, use the global keyword.

6. Two functions can have local variables with the same name without conflict. True. Each function has its own local namespace. Two functions can each have a local variable called x, and they are completely independent — no conflict.

7. Python creates a new local namespace every time a function is called. True. Each function call creates a new local namespace. This is why recursive calls each have their own set of local variables.

8. The del keyword can be used to remove a variable from the global scope. True. del removes a name from the current namespace. For example, del x removes the global variable x from the module's namespace.

9. If a variable is not found in local, enclosing, or global scopes, Python raises a NameError. True. If Python searches through Local, Enclosing, and Global scopes and does not find the name, and it is not a built-in, a NameError is raised.

10. The built-in namespace is created when the Python interpreter starts. True. The built-in namespace is created when the Python interpreter starts and contains all built-in functions and exceptions (like len, print, ValueError, etc.). It is the outermost scope.


IV. Match the Following

Set A

AB
1. Local scopec. Variables inside a function
2. Global scopee. Variables at the module level
3. Enclosing scopea. Variables in the outer function of nested functions
4. Built-in scoped. Python's pre-defined names like len, print
5. global keywordb. Allows modifying a global variable inside a function

Set B

AB
1. nonlocalc. Modifies an enclosing-scope variable
2. Closuree. Remembers enclosing-scope variables
3. Shadowinga. Local variable hides a global of the same name
4. Namespaced. Container mapping names to objects
5. LEGBb. Order: Local → Enclosing → Global → Built-in

V. Short Answer Questions

1. What is scope? Explain the different types of scope in Python.
Answer

Scope refers to the region of a program where a variable name is accessible. Python has four types of scope (LEGB rule):

1. Local (L): Variables defined inside the current function. Accessible only within that function.

   def func():
       x = 10   # Local variable
       print(x) # 10

2. Enclosing (E): Variables in the outer function of nested functions. Accessible to inner functions.

   def outer():
       y = 20   # Enclosing variable
       def inner():
           print(y)  # 20 (accesses enclosing scope)
       inner()

3. Global (G): Variables defined at the module level (outside all functions). Accessible throughout the module.

   z = 30     # Global variable
   def func():
       print(z)  # 30

4. Built-in (B): Python's pre-defined names like len, print, max, int, str. Accessible everywhere.

   print(len("hello"))  # 5 (len is built-in)

Python searches for a name in LEGB order: Local → Enclosing → Global → Built-in.


2. Explain the LEGB rule with an example.
Answer

The LEGB rule determines the order in which Python searches for a variable name: Local → Enclosing → Global → Built-in.

# Built-in scope
len   # Built-in function

# Global scope
x = "global"

def outer():
    # Enclosing scope
    x = "enclosing"

    def inner():
        # Local scope
        x = "local"
        print(x)   # Finds 'x' in Local scope → "local"

    inner()

outer()

If we remove the local x:

x = "global"

def outer():
    x = "enclosing"

    def inner():
        # No local x defined
        print(x)   # Finds 'x' in Enclosing scope → "enclosing"

    inner()

outer()

If we remove the enclosing x:

x = "global"

def outer():
    # No enclosing x defined

    def inner():
        # No local x defined
        print(x)   # Finds 'x' in Global scope → "global"

    inner()

outer()

If we remove the global x:

def outer():
    def inner():
        # No local, enclosing, or global x
        print(len)  # Finds 'len' in Built-in scope → <built-in function len>
    inner()

outer()

3. What is the global keyword? Give an example.
Answer

The global keyword is used inside a function to declare that a variable refers to a module-level (global) variable, allowing the function to modify it.

Without global — creates a local variable (shadowing):

count = 0

def increment():
    count = 10   # Creates a new local variable, does NOT modify global
    print("Inside:", count)  # 10

increment()
print("Outside:", count)  # 0 (global unchanged)

With global — modifies the global variable:

count = 0

def increment():
    global count   # Declares that 'count' refers to the global variable
    count = count + 1
    print("Inside:", count)

increment()  # Inside: 1
increment()  # Inside: 2
print("Outside:", count)  # 2 (global modified)

Key rules:

  • Use global only when you need to modify a global variable inside a function.
  • Reading a global variable does not require global.
  • Overusing global makes code harder to debug; prefer passing parameters and returning values.

4. What is the nonlocal keyword? How is it different from global?
Answer

The nonlocal keyword is used inside a nested function to declare that a variable refers to a variable in the enclosing (outer) function scope, allowing the inner function to modify it.

Example:

def outer():
    x = 10
    def inner():
        nonlocal x   # Refers to x in outer()
        x = 20       # Modifies outer's x
        print("Inner:", x)  # 20
    inner()
    print("Outer:", x)  # 20 (modified by inner)

outer()

Difference between global and nonlocal:

Featureglobalnonlocal
Scope targetedModule-level (global) variableEnclosing function's variable
Use caseModify a global variable inside a functionModify an enclosing variable in a nested function
LevelTop-level scopeOne level up in nested functions
Exampleglobal count to modify module's countnonlocal x to modify outer function's x
x = "global"

def outer():
    x = "enclosing"
    def inner():
        global x      # Refers to the module-level x
        x = "modified global"

        # nonlocal x  would refer to outer's x instead
    inner()

outer()
print(x)  # "modified global"

5. What is a closure? Give an example.
Answer

A closure is a nested function that remembers and can access variables from its enclosing scope even after the outer function has finished executing.

Key characteristics:

  • The inner function is returned by the outer function (not called inside it).
  • The inner function references variables from the enclosing scope.
  • The enclosed variables persist as long as the closure exists.

Example — Counter using closure:

def make_counter():
    count = 0           # Enclosing variable

    def increment():
        nonlocal count  # Modify enclosing variable
        count += 1
        return count

    return increment    # Return the inner function (not call it)

counter = make_counter()
print(counter())  # 1
print(counter())  # 2
print(counter())  # 3

Even though make_counter() has finished executing, increment() still has access to count because it forms a closure over count.

Example — Multiplier using closure:

def make_multiplier(factor):
    def multiply(number):
        return number * factor  # 'factor' from enclosing scope
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

Each call to make_multiplier() creates a new closure with its own factor. double remembers factor=2, and triple remembers factor=3.


6. What is a namespace? What are the different types of namespaces in Python?
Answer

A namespace is a container that maps names (identifiers) to objects. It ensures that names are unique and can be managed without conflict.

Types of namespaces in Python:

1. Built-in namespace: Contains Python's built-in names (functions, exceptions, etc.). Created when the interpreter starts.

  • Examples: len, print, max, ValueError, True

2. Global namespace: Contains names defined at the module level. Created when the module is imported or executed.

  • Examples: module-level variables, function definitions, class definitions

3. Enclosing namespace: Contains names in the outer function(s) of nested functions. Created when the outer function is called.

  • Examples: variables defined in outer() accessible to inner()

4. Local namespace: Contains names defined inside the current function. Created each time the function is called and destroyed when it returns.

  • Examples: parameters, local variables
# Built-in namespace: len, print, int, etc.

x = "global"           # Global namespace

def outer():
    y = "enclosing"     # Enclosing namespace

    def inner():
        z = "local"     # Local namespace
        print(len([1,2,3]))  # Built-in namespace

    inner()

outer()

Lifetime of namespaces:

  • Built-in: exists as long as the interpreter runs.
  • Global: exists as long as the module is loaded.
  • Enclosing/Local: exists only during function execution.

VI. Detailed Answer Questions

1. Explain the LEGB rule in detail with examples showing how Python resolves variable names at each level.
Answer

The LEGB rule defines the order in which Python searches for a variable name when it is referenced. Python checks each scope from innermost to outermost:

L — Local: Inside the current function. E — Enclosing: In the enclosing function(s) for nested functions. G — Global: At the module (top-level) scope. B — Built-in: Python's pre-defined names.

Comprehensive example:

# Built-in scope
str = "built-in would be here, but we shadow it"

# Global scope
message = "I am global"

def outer():
    # Enclosing scope
    message = "I am enclosing"

    def inner():
        # Local scope
        message = "I am local"
        print(message)     # Local: "I am local"

    inner()
    print(message)         # Enclosing: "I am enclosing"

outer()
print(message)             # Global: "I am global"

Removing local — Python looks to enclosing:

message = "I am global"

def outer():
    message = "I am enclosing"

    def inner():
        # No local 'message' defined
        print(message)     # Enclosing: "I am enclosing"

    inner()

outer()

Removing enclosing — Python looks to global:

message = "I am global"

def outer():
    # No enclosing 'message'

    def inner():
        # No local 'message'
        print(message)     # Global: "I am global"

    inner()

outer()

Removing global — Python looks to built-in:

def outer():
    def inner():
        print(len)   # Built-in: <built-in function len>
    inner()

outer()

Important: Assignment creates a local variable (by default)

x = 10

def func():
    print(x)   # Reading: OK — finds global x
func()

# But:
x = 10

def func():
    print(x)   # UnboundLocalError!
    x = 20     # Assignment makes x local; print(x) is before assignment

func()
# Python sees 'x = 20' and treats x as local for the ENTIRE function.
# print(x) comes before assignment, so x is unbound → UnboundLocalError
SolutionUse global or nonlocal to modify outer variables.

2. Explain local, global, and enclosing scopes with examples. Show how global and nonlocal keywords modify variables in outer scopes.
Answer

Local scope: Variables defined inside a function are local. They exist only during the function call and are destroyed when the function returns.

def greet():
    name = "Kavi"   # Local variable
    print(f"Hello, {name}")

greet()       # Hello, Kavi
# print(name) # NameError: name 'name' is not defined

Global scope: Variables defined outside all functions are global. They can be read inside any function, but modifying them requires global.

counter = 0   # Global variable

def show():
    print(counter)   # Reading global: OK → 0

show()

Modifying global with global:

counter = 0

def increment():
    global counter     # Declare counter as global
    counter += 1

increment()
increment()
print(counter)  # 2

Enclosing scope (nested functions): Variables in an outer function are accessible to the inner function. Modifying them requires nonlocal.

def outer():
    x = "enclosing"

    def inner():
        print(x)   # Reads enclosing x → "enclosing"

    inner()

outer()

Modifying enclosing scope with nonlocal:

def outer():
    count = 0

    def inner():
        nonlocal count    # Declare count as nonlocal
        count += 1
        return count

    inner()
    inner()
    print(count)  # 2 (modified by inner)

outer()

Summary table:

KeywordScope targetedWhen to use
globalModule-level variableTo modify a global variable inside a function
nonlocalEnclosing function's variableTo modify an enclosing variable in a nested function

Combined example:

x = "global"

def outer():
    x = "enclosing"

    def inner():
        x = "local"
        print("1. Local:", x)      # "local"

    inner()
    print("2. Enclosing:", x)       # "enclosing"

outer()
print("3. Global:", x)             # "global"

3. Explain closures in Python with multiple examples. Why are closures useful?
Answer

A closure is a nested function that retains access to variables from its enclosing scope even after the outer function has finished executing.

Conditions for a closure: 1. There must be a nested function (function inside a function). 2. The inner function must refer to a variable from the enclosing scope. 3. The outer function must return the inner function (not call it).

Example 1 — Simple closure:

def outer(message):
    def inner():
        print(message)   # 'message' from enclosing scope

    return inner        # Return inner function (not call it)

hi = outer("Hello!")
hi()   # Hello! — inner still remembers message="Hello!"

bye = outer("Goodbye!")
bye()   # Goodbye! — a separate closure with message="Goodbye!"

Example 2 — Counter closure:

def make_counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

c1 = make_counter()
print(c1())  # 1
print(c1())  # 2
print(c1())  # 3

c2 = make_counter()   # New closure with its own count
print(c2())  # 1
print(c2())  # 2

Each call to make_counter() creates a new closure with its own count. c1 and c2 are independent counters.

Example 3 — Power function using closure:

def make_power(exp):
    def power(base):
        return base ** exp   # 'exp' from enclosing scope
    return power

square = make_power(2)
cube = make_power(3)

print(square(5))  # 25  (5 ** 2)
print(cube(3))    # 27  (3 ** 3)

Why closures are useful: 1. Data hiding: The enclosed variable is not directly accessible from outside — it can only be accessed through the closure. 2. State retention: Closures remember values between calls without using global variables. 3. Function factories: Closures can create specialised functions (like square and cube from make_power). 4. Avoiding global variables: Closures provide a clean way to maintain state without polluting the global namespace. 5. Callback functions: Closures are commonly used in event handlers and asynchronous programming.


4. Explain Python namespaces in detail. How do they relate to scope?
Answer

A namespace is a mapping from names to objects. It ensures that names are unique and prevents naming conflicts.

Types of namespaces:

NamespaceCreated whenDestroyed whenContains
Built-inInterpreter startsInterpreter stopslen, print, max, int, True
GlobalModule is imported/executedModule is unloadedModule-level variables, functions, classes
EnclosingOuter function is calledOuter function returnsVariables in outer function
LocalFunction is calledFunction returnsParameters, local variables

Example showing all namespaces:

# Built-in namespace: len, print, max, etc.

# Global namespace
PI = 3.14159           # Global variable

def circle_area():     # Global name
    pass

def outer(enclosed_param):   # Global name 'outer'
    # Enclosing namespace
    enclosed_var = 10

    def inner(local_param):   # Enclosing name 'inner'
        # Local namespace
        local_var = enclosed_param + enclosed_var
        result = max(local_var, 5)   # 'max' from built-in
        print(result)                  # 'print' from built-in
        return result

    return inner

func = outer(20)
print(func(5))   # 25

How namespaces relate to scope:

  • Scope is the textual area of a program where a namespace is directly accessible.
  • When you reference a name, Python searches namespaces in LEGB order.
  • Each function call creates a new local namespace.
  • The globals() function returns the current global namespace as a dictionary.
  • The locals() function returns the current local namespace as a dictionary.

Demonstrating globals() and locals():

x = 10

def func(a, b):
    c = a + b
    print("Local namespace:", locals())
    return c

func(3, 5)
# Local namespace: {'a': 3, 'b': 5, 'c': 8}

print("Global 'x' in globals:", 'x' in globals())  # True

5. Explain shadowing in Python. What problems does it cause and how can they be avoided?
Answer

Shadowing occurs when a variable in an inner scope has the same name as a variable in an outer scope. The inner variable "shadows" (hides) the outer one within its scope.

Example of shadowing:

x = 100           # Global

def func():
    x = 200        # Local variable shadows global x
    print(x)       # 200 (local x)

func()
print(x)           # 100 (global x is unaffected)

Common shadowing scenarios:

1. Local shadows global:

name = "Global"

def greet():
    name = "Local"     # Shadows global 'name'
    print(name)       # "Local"

greet()
print(name)           # "Global"

2. Shadowing built-in names (dangerous):

# NEVER do this:
len = 50          # Shadows the built-in len() function!
# print(len([1, 2, 3]))  # TypeError: 'int' object is not callable

3. Local shadows enclosing:

def outer():
    x = "enclosing"

    def inner():
        x = "local"    # Shadows enclosing 'x'
        print(x)      # "local"

    inner()
    print(x)          # "enclosing" (unchanged)

outer()

Problems caused by shadowing:

  • Confusion: It is unclear which variable is being referenced.
  • Bugs: Unintended shadowing can lead to hard-to-find errors.
  • Shadowing built-ins: Accidentally shadowing len, list, str, etc. can break code.
  • UnboundLocalError: Assigning to a variable anywhere in a function makes it local for the entire function, even before the assignment.
x = 10

def func():
    print(x)   # UnboundLocalError!
    x = 20     # This makes x local for the ENTIRE function

func()

How to avoid shadowing problems: 1. Use distinct, descriptive variable names instead of generic names like x, y, tmp. 2. Never name variables after built-in functions (len, list, str, dict, max, min). 3. Use global or nonlocal when you intentionally want to modify an outer variable. 4. Keep functions small and focused to reduce the chance of accidental shadowing. 5. Use linters (like pylint) to detect shadowing warnings.


Common Mistakes

1. Forgetting global when modifying a global variable: Assigning to a variable inside a function creates a local variable by default. Use global to modify a global variable.

2. Forgetting nonlocal when modifying an enclosing variable: Same issue as global, but for nested functions. Use nonlocal to modify an enclosing variable.

3. UnboundLocalError from assignment after reference: If you assign to a variable anywhere in a function, Python treats it as local for the entire function. Referencing it before the assignment causes UnboundLocalError.

4. Shadowing built-in names: Naming a variable list, str, len, or dict shadows the built-in. This can cause TypeError when you later try to use the built-in.

5. Confusing global and nonlocal: Use global for module-level variables and nonlocal for enclosing-function variables. Using the wrong keyword causes a SyntaxError.

6. Expecting closures to share state across instances: Each call to the outer function creates a new closure with its own enclosed variables. Two closures from the same outer function do not share state.

7. Assuming local variables persist between function calls: Local variables are destroyed when the function returns. Use closures or global variables if you need state persistence.


Exam Checklist

  • [ ] Can define scope and explain the four types (Local, Enclosing, Global, Built-in)
  • [ ] Can explain the LEGB rule and trace variable resolution through each level
  • [ ] Can explain the difference between local and global variables
  • [ ] Can use the global keyword to modify a global variable inside a function
  • [ ] Can use the nonlocal keyword to modify an enclosing variable in a nested function
  • [ ] Can define namespace and list its types
  • [ ] Can explain closures with examples (counter, multiplier, power factory)
  • [ ] Can explain shadowing and its problems
  • [ ] Can predict output of code involving scope, global, and nonlocal
  • [ ] Know that assignment in a function makes the variable local for the entire function

Frequently Asked Questions

The LEGB rule defines the order in which Python searches for a variable name: Local (inside the current function), Enclosing (in enclosing functions), Global (at the module level), and Built-in (Python's built-in names). Python checks each scope in this order.
← Browse all Class 12 Exercise Solutions

Other question types — same chapter