Little tadpoles looking for mother: Python’s scope chain and LEGB principle

Article directory

  • refer to
  • describe
  • scope object
      • global scope
          • globals()
      • local scope
          • locals()
      • contains scope
      • built-in scope
          • builtins module
            • builtins module with \_\_builtins__
            • builtins is \_\_builtins__?
          • \_\_builtins__ and built-in scopes
          • The irreplaceable \_\_builtins__
  • scope chain
      • Scope chains and the LEGB principle
      • The method of jumping over the wall in a hurry

Reference

Project Description
Python Official Documentation builtins.html
Search Engines Google, Bing

Description

Project Description
PyCharm 2023.1 (Professional Edition)
Python 3.10.6

Scope object

Scope Object (Scope Object) is an internal data structure used to manage namespaces in Python, which is an important part maintained and used by the Python interpreter during code execution.

Whenever a new function, class, or module is created, the Python interpreter creates a corresponding scope object to keep track of the variables, functions, and other named items within that scope. Scope objects form a hierarchy, which facilitates the lookup and access of variables and namespaces according to specific rules.

The scope object mainly plays the following roles:

Project Description
Namespace A scope object maintains a namespace for storing variables, functions, and other named items defined in that scope. A namespace can be thought of as a dictionary where the keys are the names and the values are the objects associated with the names.
Variable lookup When a variable is referenced in the scope, the Python interpreter will follow the specific The rule looks for the variable in the scope object’s namespace.
Naming Conflict Resolution Scope objects help resolve possible naming conflicts within the same scope, ensuring that each Names are unique within their namespace. When multiple variables or functions with the same name are defined in a scope, the scope object ensures that each name is unique within its namespace to avoid confusion and mistake.
Scope chain Scope objects are created by building a nested list structure Implement variable and namespace lookups. The linked list links all nested scope objects in a specific order, so that the interpreter can search in different scopes in the specified order.
Scope switching When the program execution flow enters or leaves a scope, the scope object is responsible for managing the current activity The state of the scope. Scope objects will be created when the program execution flow enters scope and cleaned up when they leave scope to ensure proper namespace access and lifecycle management .

Global scope

Global Scope (Global Scope) refers to the scope visible throughout the program at the module level. It is the scope of the variables, functions and classes defined in the module.

In Python, the global scope (Global Scope) refers to the whole program visible, at the module level scope. The global scope contains variables, functions, classes, and other named items defined in the global scope. The global scope is created when the program starts, and always exists throughout the execution of the program.
The global scope is closely related to modules in Python. Each Python file can be regarded as a module, and the module has its own global scope. Global variables and functions defined in a module can be accessed and used throughout the module.

globals()

globals() is a built-in function that returns a dictionary representing the global namespace of the current module, which stores all global variables and functions defined in the current module.

Give me a chestnut

free_var = 'Hello World'

# The result of globals() access anywhere in the program is
# Consistent.
for name in globals().copy():
    print(f'{<!-- -->name}\t{<!-- -->globals()[name]}')


# When calling the globals() function, MyClass
Neither # nor func have been added to the global namespace.
# Only the interpreter executes to the definition part of MyClass and func
# Python will add it to the global namespace.
class MyClass:
    pass


print()
print('MyClass' in globals())
print('func' in globals())
print()


def func():
    pass


print('MyClass' in globals())
print('func' in globals())

Execution effect

When the interpreter loads a module (any Python file can be considered a module), it will first create a new global scope object for storing the module’s global variables, functions, classes and other definitions. The interpreter parses the code in the module in order, and binds identifiers to the corresponding scope objects during execution.

__name____main__
__doc__ None
__package__ None
__loader__ <_frozen_importlib_external. SourceFileLoader object at 0x000002868F414820>
__spec__ None
__annotations__ {}
__builtins__ <module 'builtins' (built-in)>
__file__ C:\Users\RedHeart\PycharmProjects\pythonProject\example.py
__cached__ None
free_var Hello World

True
False

True
True

Local scope

In Python, whenever a function is called, a new local scope object is created for it. This means that every function has its own separate local scope in which variables defined only exist during the execution of the function, when the function returns code>, the local scope and its variables are destroyed.
Local scopes provide a mechanism for encapsulating variables so that they do not collide with variables in other functions or the global scope. This helps improve code readability, maintainability, and reusability.

locals()

In Python, locals() is a built-in function that returns a dictionary of local variables and their corresponding values in the current scope, where the keys are variable names, value is the value of the corresponding variable. For this, please refer to the following example:

# When the locals() function is called in the global scope,
# This function will return the global namespace dictionary, same as globals()
# returns the same value.
print(locals() == globals())


def func():
    # When calling the locals() function in a function,
    # This function will return the local namespace dictionary of the function it is in.
    local_var = 'Hello World'
    print(locals())


func()

Execution effect

True
{<!-- -->'local_var': 'Hello World'}

Include scope

A containing scope occurs when another scope is defined inside a local scope (for example, another function is defined inside a function). In nested function-level scopes, the innermost scope is called the local scope, and the other scopes are called containing scopes.

Give me a chestnut

# global scope
def external_func():
    # include scope
    def middle_func():
        # include scope
        def internal_func():
            # local scope
            pass

Built-in scope

In Python, built-in scope (Built-in Scope) refers to a set of functions and variables predefined by the Python interpreter, which can be used directly anywhere without importing other modules.

The built-in scope contains some commonly used objects (such as print(), len(), range(), True etc.) to perform a variety of common tasks and operations. These objects can be directly accessed by all Python code, without needing to explicitly import any modules.

builtins module

In Python, the builtins module is a built-in module that contains Python’s built-in functions, exceptions, and some other built-in objects. This module will be automatically loaded when the Python interpreter starts, so you can directly access the objects defined in it without having to import it explicitly.

The builtins module provides many commonly used built-in functions and built-in objects, such as:

  • print(): used to output text to the console.
  • input(): Used to read user input from the console.
  • len(): Used to get the length of the object.
  • int(), float(), str() and other type conversion functions.
  • Abnormal classes such as Exception, TypeError, ValueError, etc.
  • abs(), round(), min(), max() and other common functions.
builtins module and __builtins__

In Python, __builtins__ is a special global variable that points to a dictionary containing the namespaces of built-in functions, exceptions, and objects. In the global scope of the module, these built-in functions and objects can be accessed through __builtins__.

When the builtins module is imported using import builtins, the builtins module itself is loaded and a module object is created. Then, the module object’s __dict__ (the __dict__ attribute is a dictionary used to store object instance variables and methods) attribute will be used to initialize __builtins__ variable so that it points to the namespace of the builtins module.

Therefore, it can be said that __builtins__ is the result of importing the builtins module into the module. Through __builtins__, you can access the built-in functions and objects provided by the builtins module in the module, such as __builtins__.print(), __builtins__ .len() etc.

builtins is __builtins__?

In Python, when the same module is imported multiple times, the loading and initialization process of the module is actually only performed once. Subsequent import operations will directly refer to the loaded module object without re-executing the code in the module.

This means that multiple imports of the same module will not cause the code within the module to be executed repeatedly. Only at the first import, the code inside the module will be executed once and the module object will be created. Subsequent import operations will simply refer to the loaded module object.

The Python interpreter automatically imports the builtins module when running a Python file, and explicitly importing the builtins module will directly reference the loaded builtins module object. Therefore, the result of builtins is __builtins__ will be True.

__builtins__ and built-in scope

In Python, built-in scope objects can be accessed by accessing the global variable __builtins__. __builtins__ is a special global variable that points to a module object that contains Python’s built-in objects.

The __builtins__ that can’t be driven away

In Python, imported modules can be deleted with the __del__ keyword. For this, please refer to the following example:

# Determine whether the sys module has been imported
print('sys' in globals())

# import sys module
import sys

print('sys' in globals())

# Attempt to delete the imported module sys using the del keyword
del sys

print('sys' in globals())

Execution effect

False
True
False

But for the builtins object that Python automatically imports into the global scope, you cannot delete it by any means. This is because, builtins is part of the interpreter, it is created when the interpreter starts and remains constant throughout the lifetime of the interpreter. Therefore, we cannot delete or modify builtins by normal methods.
You can delete or modify the global variable form __builtins__ of built-in scope objects provided by Python, but this does not prevent the Python interpreter from using the basic components provided by the builtins module. For this, please refer to the following example:

print('__builtins__' in globals())

# Try to delete the __builtins__ variable using the del keyword
del __builtins__

# Built-in objects like print(), globals() and in can still be used
print('__builtins__' in globals())

Scope chain

Scope chaining and the LEGB principle

LEGB Principles Scope chain and Scope chain are closely related concepts used to describe the order in which variables are looked up and accessed.
LEGB refers to the four levels of object lookup in Python, which are local scope, containing scope, global scope and built-in scope.

The scope chain describes the order in which variables are looked up, and it is formed according to the LEGB principle. When an object is referenced in code, Python will find the object in LEGB order until it finds the first variable that matches.

Here’s an example showing scope chaining and the LEGB principle in action:

# Variables defined in the built-in scope
__builtins__.k = 40

# Variables defined in the global scope
x = 10

def outer():
    # Include variables defined in the scope
    y = 20

    def inner():
        # Variables defined in local scope
        z = 30
        # Since the variable y is found in the local scope,
        # So no longer look up the value of y along the scope chain, so y = 30.
        y = 30
        # 10 + 30 + 30 + 40 = 110
        print(x + y + z + k)

    inner()


outer()

Execution effect

110

The method of dog jumping over the wall

According to the LEGB principle, when there is an object with the same name as the built-in object in a scope other than the built-in scope, the built-in object will be covered by other objects with the same name.
In Python, when there is an object with the same name that overrides the built-in object provided by Python, you can use __builtins__ to refer to the original built-in object. For this, please refer to the following example:

def print(content):
    pass


# The built-in object print() has been shadowed by the function print() of the same name in the global scope
print('Hello World')

# Direct access to built-in objects by using the __builtins__ global variable access
__builtins__. print('Hello China')

Execution effect

Hello China