locals() - 局部命名空间函数

返回当前局部命名空间的字典

分类: builtins 难度: 中级 更新: 2024-01-15
命名空间 局部变量 作用域 变量管理

locals() - 局部命名空间函数

📝 概述

locals() 是 Python 中的内置函数,用于返回当前局部命名空间的字典。这个字典包含了当前作用域中的所有局部变量。在模块级别调用时,locals() 的行为与 globals() 相同。在函数内部调用时,它返回函数的局部变量字典。需要注意的是,对 locals() 返回字典的修改可能不会影响实际的局部变量。

🎯 学习目标

  • 掌握 locals()函数的基本用法和特性
  • 理解局部命名空间的概念和作用域
  • 学会在不同上下文中使用 locals()
  • 掌握 locals()在调试和内省中的应用
  • 了解 locals()与 globals()的区别和联系

📋 前置知识

  • Python 基本语法
  • 变量作用域的概念
  • 函数定义和调用
  • 字典操作基础
  • 理解全局和局部变量的区别

🔍 详细内容

基本概念

局部命名空间是 Python 中存储局部变量的字典,其内容取决于调用 locals() 的上下文:

  1. 模块级别: 返回全局命名空间(等同于 globals()
  2. 函数内部: 返回函数的局部变量
  3. 类定义内部: 返回类的局部命名空间
  4. 方法内部: 返回方法的局部变量

语法格式

locals()

参数说明

locals() 函数不接受任何参数。

返回值

  • 类型: 字典(dict)
  • 内容: 当前局部命名空间中的所有名称和对应的对象

重要特性

  1. 只读性: 对返回字典的修改通常不会影响实际的局部变量
  2. 上下文相关: 返回内容取决于调用位置
  3. 动态性: 每次调用都返回当前状态的快照

💡 代码示例

基本用法

## 基本用法示例
print("locals()基本用法:")

## 模块级别的 locals()
module_var1 = "模块变量 1"
module_var2 = 42

print(f"\n1. 模块级别的 locals():")
module_locals = locals()
print(f"locals()类型: {type(module_locals)}")
print(f"变量数量: {len(module_locals)}")

## 检查模块级别 locals()是否等同于 globals()
print(f"locals() is globals(): {locals() is globals()}")
print(f"模块变量在 locals()中: {'module_var1' in module_locals}")

## 函数中的 locals()
def demonstrate_function_locals():
    """演示函数中的 locals()"""
    func_var1 = "函数变量 1"
    func_var2 = [1, 2, 3]
    func_var3 = {'key': 'value'}
    
    print(f"\n2. 函数中的 locals():")
    func_locals = locals()
    print(f"函数局部变量数量: {len(func_locals)}")
    print(f"局部变量列表:")
    
    for name, value in func_locals.items():
        print(f"  {name}: {value} ({type(value).__name__})")
    
    return func_locals

## 调用函数
function_locals_result = demonstrate_function_locals()

## 带参数的函数
def function_with_parameters(param1, param2, *args, **kwargs):
    """带参数的函数"""
    local_var = "局部变量"
    
    print(f"\n3. 带参数函数的 locals():")
    func_locals = locals()
    
    print(f"参数和局部变量:")
    for name, value in func_locals.items():
        print(f"  {name}: {value}")
    
    return func_locals

## 测试带参数的函数
params_result = function_with_parameters("arg1", "arg2", "extra1", "extra2", key1="value1", key2="value2")

## 嵌套函数中的 locals()
def outer_function(outer_param):
    """外层函数"""
    outer_var = "外层变量"
    
    def inner_function(inner_param):
        """内层函数"""
        inner_var = "内层变量"
        
        print(f"\n4. 嵌套函数的 locals():")
        print(f"内层函数 locals():")
        inner_locals = locals()
        for name, value in inner_locals.items():
            print(f"  {name}: {value}")
        
        return inner_locals
    
    print(f"外层函数 locals():")
    outer_locals = locals()
    for name, value in outer_locals.items():
        if not callable(value):  # 不显示函数对象
            print(f"  {name}: {value}")
    
    return inner_function("内层参数")

## 测试嵌套函数
nested_result = outer_function("外层参数")

locals()的修改行为

## locals()修改行为示例
print("\nlocals()修改行为示例:")

## 模块级别的修改
print("1. 模块级别修改:")
original_value = "原始值"
print(f"修改前: original_value = {original_value}")

## 在模块级别,locals()等同于 globals(),修改会生效
locals()['original_value'] = "修改后的值"
print(f"修改后: original_value = {original_value}")

## 函数级别的修改(通常不会生效)
def test_local_modification():
    """测试局部变量修改"""
    print(f"\n2. 函数级别修改:")
    
    local_var = "原始局部值"
    print(f"修改前: local_var = {local_var}")
    
#    # 尝试通过 locals()修改局部变量
    local_dict = locals()
    local_dict['local_var'] = "尝试修改的值"
    
    print(f"修改 locals()后: local_var = {local_var}")
    print(f"locals()字典中的值: {locals()['local_var']}")
    
#    # 直接修改变量
    local_var = "直接修改的值"
    print(f"直接修改后: local_var = {local_var}")
    
    return locals()

test_result = test_local_modification()

## 演示为什么函数中的 locals()修改不生效
def explain_locals_behavior():
    """解释 locals()行为"""
    print(f"\n3. locals()行为解释:")
    
    var1 = "变量 1"
    var2 = "变量 2"
    
#    # 获取 locals()的引用
    local_dict = locals()
    print(f"获取 locals()引用")
    
#    # 修改字典
    local_dict['var1'] = "修改的变量 1"
    local_dict['new_var'] = "新变量"
    
    print(f"修改字典后:")
    print(f"  var1 = {var1}")
    print(f"  var2 = {var2}")
    print(f"  'new_var' in locals(): {'new_var' in locals()}")
    
#    # 再次调用 locals()查看
    current_locals = locals()
    print(f"\n 再次调用 locals():")
    for name, value in current_locals.items():
        print(f"  {name}: {value}")

explain_locals_behavior()

## 安全的局部变量检查
def safe_locals_inspection():
    """安全的局部变量检查"""
    print(f"\n4. 安全的局部变量检查:")
    
    inspection_var1 = "检查变量 1"
    inspection_var2 = [1, 2, 3, 4, 5]
    inspection_var3 = {'a': 1, 'b': 2}
    
#    # 创建 locals()的副本进行安全操作
    locals_copy = locals().copy()
    
    print(f"局部变量快照:")
    for name, value in locals_copy.items():
        if not name.startswith('locals_copy'):
            print(f"  {name}: {value} ({type(value).__name__})")
    
#    # 分析变量类型
    type_counts = {}
    for value in locals_copy.values():
        type_name = type(value).__name__
        type_counts[type_name] = type_counts.get(type_name, 0) + 1
    
    print(f"\n 变量类型统计:")
    for type_name, count in type_counts.items():
        print(f"  {type_name}: {count}")
    
    return locals_copy

safe_inspection_result = safe_locals_inspection()

类中的 locals()使用

## 类中的 locals()使用示例
print("\n 类中的 locals()使用示例:")

## 类定义中的 locals()
print("1. 类定义中的 locals():")

class DemoClass:
    """演示类"""
    class_var1 = "类变量 1"
    class_var2 = 42
    
#    # 在类定义中使用 locals()
    print(f"类定义中的 locals():")
    class_locals = locals()
    print(f"  类局部变量数量: {len(class_locals)}")
    for name, value in class_locals.items():
        if not name.startswith('__'):
            print(f"    {name}: {value}")
    
    def __init__(self, instance_param):
        """初始化方法"""
        self.instance_var = instance_param
        
        print(f"\n2. __init__方法中的 locals():")
        init_locals = locals()
        for name, value in init_locals.items():
            print(f"  {name}: {value}")
    
    def instance_method(self, method_param):
        """实例方法"""
        method_var = "方法变量"
        
        print(f"\n3. 实例方法中的 locals():")
        method_locals = locals()
        for name, value in method_locals.items():
            print(f"  {name}: {value}")
        
        return method_locals
    
    @classmethod
    def class_method(cls, class_param):
        """类方法"""
        class_method_var = "类方法变量"
        
        print(f"\n4. 类方法中的 locals():")
        class_method_locals = locals()
        for name, value in class_method_locals.items():
            print(f"  {name}: {value}")
        
        return class_method_locals
    
    @staticmethod
    def static_method(static_param):
        """静态方法"""
        static_var = "静态方法变量"
        
        print(f"\n5. 静态方法中的 locals():")
        static_locals = locals()
        for name, value in static_locals.items():
            print(f"  {name}: {value}")
        
        return static_locals

## 测试类中的 locals()
demo_instance = DemoClass("实例参数")
instance_result = demo_instance.instance_method("方法参数")
class_result = DemoClass.class_method("类参数")
static_result = DemoClass.static_method("静态参数")

## 属性访问中的 locals()
class PropertyDemo:
    """属性演示类"""
    
    def __init__(self):
        self._value = 0
    
    @property
    def value(self):
        """属性 getter"""
        getter_var = "getter 变量"
        
        print(f"\n6. 属性 getter 中的 locals():")
        getter_locals = locals()
        for name, value in getter_locals.items():
            print(f"  {name}: {value}")
        
        return self._value
    
    @value.setter
    def value(self, new_value):
        """属性 setter"""
        setter_var = "setter 变量"
        old_value = self._value
        
        print(f"\n7. 属性 setter 中的 locals():")
        setter_locals = locals()
        for name, value in setter_locals.items():
            print(f"  {name}: {value}")
        
        self._value = new_value

## 测试属性中的 locals()
prop_demo = PropertyDemo()
value = prop_demo.value  # 触发 getter
prop_demo.value = 42     # 触发 setter

调试和内省应用

import inspect
import traceback
from typing import Dict, Any, List, Optional

## 调试和内省工具
class LocalsInspector:
    """局部变量检查器"""
    
    def __init__(self):
        self.inspection_history = []
    
    def inspect_current_locals(self, frame_offset: int = 1) -> Dict[str, Any]:
        """检查当前局部变量"""
#        # 获取调用者的帧
        frame = inspect.currentframe()
        try:
#            # 向上查找指定层数的帧
            for _ in range(frame_offset):
                frame = frame.f_back
                if frame is None:
                    return {'error': 'Frame not found'}
            
#            # 获取局部变量
            frame_locals = frame.f_locals.copy()
            
#            # 获取帧信息
            frame_info = {
                'filename': frame.f_code.co_filename,
                'function': frame.f_code.co_name,
                'line_number': frame.f_lineno,
                'locals_count': len(frame_locals)
            }
            
            inspection_result = {
                'frame_info': frame_info,
                'locals': frame_locals,
                'timestamp': __import__('time').time()
            }
            
            self.inspection_history.append(inspection_result)
            return inspection_result
            
        finally:
            del frame  # 避免循环引用
    
    def debug_function_call(self, func, *args, **kwargs):
        """调试函数调用"""
        print(f"\n 调试函数调用: {func.__name__}")
        
#        # 调用前检查
        print(f"调用前的局部变量:")
        pre_locals = self.inspect_current_locals()
        for name, value in pre_locals['locals'].items():
            if not name.startswith('_'):
                print(f"  {name}: {value}")
        
        try:
#            # 执行函数
            result = func(*args, **kwargs)
            
#            # 调用后检查
            print(f"\n 调用后的局部变量:")
            post_locals = self.inspect_current_locals()
            for name, value in post_locals['locals'].items():
                if not name.startswith('_'):
                    print(f"  {name}: {value}")
            
            return result
            
        except Exception as e:
            print(f"\n 函数执行出错: {e}")
            print(f"错误时的局部变量:")
            error_locals = self.inspect_current_locals()
            for name, value in error_locals['locals'].items():
                if not name.startswith('_'):
                    print(f"  {name}: {value}")
            raise
    
    def analyze_variable_changes(self, var_name: str) -> List[Dict[str, Any]]:
        """分析变量变化"""
        changes = []
        
        for i, inspection in enumerate(self.inspection_history):
            if var_name in inspection['locals']:
                change_info = {
                    'inspection_index': i,
                    'timestamp': inspection['timestamp'],
                    'function': inspection['frame_info']['function'],
                    'line': inspection['frame_info']['line_number'],
                    'value': inspection['locals'][var_name],
                    'type': type(inspection['locals'][var_name]).__name__
                }
                changes.append(change_info)
        
        return changes
    
    def get_inspection_summary(self) -> Dict[str, Any]:
        """获取检查摘要"""
        if not self.inspection_history:
            return {'message': 'No inspections performed'}
        
#        # 统计信息
        total_inspections = len(self.inspection_history)
        functions_inspected = set()
        all_variables = set()
        
        for inspection in self.inspection_history:
            functions_inspected.add(inspection['frame_info']['function'])
            all_variables.update(inspection['locals'].keys())
        
        return {
            'total_inspections': total_inspections,
            'functions_inspected': len(functions_inspected),
            'unique_variables': len(all_variables),
            'function_list': list(functions_inspected),
            'common_variables': self._find_common_variables()
        }
    
    def _find_common_variables(self) -> List[str]:
        """查找常见变量"""
        if not self.inspection_history:
            return []
        
#        # 统计变量出现次数
        var_counts = {}
        for inspection in self.inspection_history:
            for var_name in inspection['locals'].keys():
                var_counts[var_name] = var_counts.get(var_name, 0) + 1
        
#        # 返回出现次数超过一半的变量
        threshold = len(self.inspection_history) // 2
        return [var for var, count in var_counts.items() if count > threshold]

## 测试调试工具
print("\n 调试和内省应用示例:")

inspector = LocalsInspector()

## 测试函数 1
def test_function1(param1, param2):
    """测试函数 1"""
    local_var1 = param1 * 2
    local_var2 = param2.upper() if isinstance(param2, str) else str(param2)
    
#    # 在函数中检查局部变量
    inspection = inspector.inspect_current_locals(0)  # 检查当前帧
    print(f"\n 函数 1 中的局部变量检查:")
    print(f"  函数: {inspection['frame_info']['function']}")
    print(f"  行号: {inspection['frame_info']['line_number']}")
    print(f"  局部变量:")
    for name, value in inspection['locals'].items():
        if not name.startswith('_'):
            print(f"    {name}: {value}")
    
    return local_var1, local_var2

## 测试函数 2
def test_function2(data_list):
    """测试函数 2"""
    processed_data = []
    total = 0
    
    for i, item in enumerate(data_list):
        processed_item = item ** 2
        processed_data.append(processed_item)
        total += processed_item
        
#        # 在循环中检查局部变量
        if i == 2:  # 只在第 3 次迭代时检查
            inspection = inspector.inspect_current_locals(0)
            print(f"\n 函数 2 循环中的局部变量检查 (i={i}):")
            for name, value in inspection['locals'].items():
                if not name.startswith('_'):
                    print(f"    {name}: {value}")
    
    average = total / len(data_list) if data_list else 0
    return processed_data, total, average

## 使用调试器测试函数
print("1. 使用调试器测试函数:")
result1 = inspector.debug_function_call(test_function1, 5, "hello")
print(f"函数 1 结果: {result1}")

result2 = inspector.debug_function_call(test_function2, [1, 2, 3, 4, 5])
print(f"函数 2 结果: {result2}")

## 分析变量变化
print(f"\n2. 变量变化分析:")
changes = inspector.analyze_variable_changes('local_var1')
if changes:
    print(f"变量 'local_var1' 的变化:")
    for change in changes:
        print(f"  函数 {change['function']}, 行 {change['line']}: {change['value']} ({change['type']})")
else:
    print(f"变量 'local_var1' 未找到变化记录")

## 获取检查摘要
print(f"\n3. 检查摘要:")
summary = inspector.get_inspection_summary()
for key, value in summary.items():
    print(f"  {key}: {value}")

高级应用:动态变量跟踪

import functools
import time
from typing import Callable, Any, Dict, List

## 动态变量跟踪器
class VariableTracker:
    """变量跟踪器"""
    
    def __init__(self):
        self.tracking_data = {}
        self.active_tracking = set()
    
    def track_function(self, track_vars: List[str] = None):
        """函数装饰器:跟踪函数中的变量"""
        def decorator(func: Callable) -> Callable:
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                func_name = func.__name__
                
#                # 初始化跟踪数据
                if func_name not in self.tracking_data:
                    self.tracking_data[func_name] = {
                        'calls': [],
                        'variable_history': {}
                    }
                
                call_start_time = time.time()
                call_id = len(self.tracking_data[func_name]['calls'])
                
#                # 执行函数并跟踪变量
                try:
#                    # 创建包装的 locals()函数
                    original_locals = locals
                    
                    def tracking_locals():
                        current_locals = original_locals()
                        
#                        # 记录指定变量的变化
                        if track_vars:
                            for var_name in track_vars:
                                if var_name in current_locals:
                                    self._record_variable_change(
                                        func_name, call_id, var_name, 
                                        current_locals[var_name]
                                    )
                        
                        return current_locals
                    
#                    # 临时替换 locals()(仅在此函数作用域内)
#                    # 注意:这只是演示,实际中不建议替换内置函数
                    
                    result = func(*args, **kwargs)
                    
#                    # 记录调用信息
                    call_info = {
                        'call_id': call_id,
                        'start_time': call_start_time,
                        'end_time': time.time(),
                        'args': args,
                        'kwargs': kwargs,
                        'result': result,
                        'success': True
                    }
                    
                    self.tracking_data[func_name]['calls'].append(call_info)
                    return result
                    
                except Exception as e:
#                    # 记录异常调用
                    call_info = {
                        'call_id': call_id,
                        'start_time': call_start_time,
                        'end_time': time.time(),
                        'args': args,
                        'kwargs': kwargs,
                        'error': str(e),
                        'success': False
                    }
                    
                    self.tracking_data[func_name]['calls'].append(call_info)
                    raise
            
            return wrapper
        return decorator
    
    def _record_variable_change(self, func_name: str, call_id: int, 
                               var_name: str, value: Any):
        """记录变量变化"""
        if var_name not in self.tracking_data[func_name]['variable_history']:
            self.tracking_data[func_name]['variable_history'][var_name] = []
        
        change_record = {
            'call_id': call_id,
            'timestamp': time.time(),
            'value': value,
            'type': type(value).__name__
        }
        
        self.tracking_data[func_name]['variable_history'][var_name].append(change_record)
    
    def get_function_stats(self, func_name: str) -> Dict[str, Any]:
        """获取函数统计信息"""
        if func_name not in self.tracking_data:
            return {'error': f'Function {func_name} not tracked'}
        
        data = self.tracking_data[func_name]
        calls = data['calls']
        
        if not calls:
            return {'message': 'No calls recorded'}
        
#        # 计算统计信息
        successful_calls = [call for call in calls if call['success']]
        failed_calls = [call for call in calls if not call['success']]
        
        if successful_calls:
            execution_times = [call['end_time'] - call['start_time'] for call in successful_calls]
            avg_execution_time = sum(execution_times) / len(execution_times)
            min_execution_time = min(execution_times)
            max_execution_time = max(execution_times)
        else:
            avg_execution_time = min_execution_time = max_execution_time = 0
        
        return {
            'total_calls': len(calls),
            'successful_calls': len(successful_calls),
            'failed_calls': len(failed_calls),
            'avg_execution_time': avg_execution_time,
            'min_execution_time': min_execution_time,
            'max_execution_time': max_execution_time,
            'tracked_variables': list(data['variable_history'].keys())
        }
    
    def get_variable_timeline(self, func_name: str, var_name: str) -> List[Dict[str, Any]]:
        """获取变量时间线"""
        if (func_name not in self.tracking_data or 
            var_name not in self.tracking_data[func_name]['variable_history']):
            return []
        
        return self.tracking_data[func_name]['variable_history'][var_name].copy()
    
    def print_tracking_report(self, func_name: str = None):
        """打印跟踪报告"""
        if func_name:
            functions_to_report = [func_name] if func_name in self.tracking_data else []
        else:
            functions_to_report = list(self.tracking_data.keys())
        
        if not functions_to_report:
            print("没有跟踪数据")
            return
        
        print(f"\n 变量跟踪报告:")
        print(f"=" * 50)
        
        for func in functions_to_report:
            stats = self.get_function_stats(func)
            
            print(f"\n 函数: {func}")
            print(f"  总调用次数: {stats['total_calls']}")
            print(f"  成功调用: {stats['successful_calls']}")
            print(f"  失败调用: {stats['failed_calls']}")
            print(f"  平均执行时间: {stats['avg_execution_time']:.4f}秒")
            print(f"  跟踪的变量: {stats['tracked_variables']}")
            
#            # 显示变量变化
            for var_name in stats['tracked_variables']:
                timeline = self.get_variable_timeline(func, var_name)
                print(f"\n  变量 '{var_name}' 的变化:")
                for i, change in enumerate(timeline[-5:]):  # 只显示最近 5 次变化
                    print(f"    {i+1}. 调用{change['call_id']}: {change['value']} ({change['type']})")

## 测试变量跟踪器
print("\n 动态变量跟踪示例:")

tracker = VariableTracker()

## 使用跟踪装饰器
@tracker.track_function(['counter', 'result', 'temp'])
def tracked_calculation(n):
    """被跟踪的计算函数"""
    counter = 0
    result = 0
    
    for i in range(n):
        counter += 1
        temp = i ** 2
        result += temp
        
#        # 模拟一些局部变量操作
        if i % 2 == 0:
            temp *= 2
    
    return result

@tracker.track_function(['data', 'processed'])
def tracked_processing(input_data):
    """被跟踪的处理函数"""
    data = input_data.copy() if hasattr(input_data, 'copy') else list(input_data)
    processed = []
    
    for item in data:
        if isinstance(item, (int, float)):
            processed_item = item * 2 + 1
            processed.append(processed_item)
    
    return processed

## 测试跟踪功能
print("1. 执行被跟踪的函数:")

## 多次调用函数
for i in range(3):
    result1 = tracked_calculation(5)
    print(f"  计算结果 {i+1}: {result1}")

for i in range(2):
    result2 = tracked_processing([1, 2, 3, 4])
    print(f"  处理结果 {i+1}: {result2}")

## 打印跟踪报告
print("\n2. 跟踪报告:")
tracker.print_tracking_report()

## 获取特定函数的详细统计
print("\n3. 详细统计:")
stats = tracker.get_function_stats('tracked_calculation')
print(f"tracked_calculation 统计:")
for key, value in stats.items():
    print(f"  {key}: {value}")

## 获取变量时间线
print("\n4. 变量时间线:")
timeline = tracker.get_variable_timeline('tracked_calculation', 'result')
print(f"变量 'result' 的完整时间线:")
for change in timeline:
    print(f"  调用{change['call_id']}: {change['value']} (时间: {change['timestamp']:.2f})")

⚠️ 常见陷阱与最佳实践

locals()的限制和注意事项

## locals()限制和注意事项
print("\nlocals()限制和注意事项:")

## 1. 修改限制
print("1. 修改限制:")

def modification_limitation_demo():
    """演示修改限制"""
    local_var = "原始值"
    
    print(f"  修改前: local_var = {local_var}")
    
#    # 尝试修改 locals()字典
    locals()['local_var'] = "修改的值"
    print(f"  尝试修改后: local_var = {local_var}")  # 通常不会改变
    
#    # 添加新变量到 locals()
    locals()['new_local'] = "新变量"
    print(f"  添加新变量后: 'new_local' in locals() = {'new_local' in locals()}")
    
#    # 但是新变量通常无法直接访问
    try:
        print(f"  直接访问 new_local: {new_local}")
    except NameError:
        print(f"  无法直接访问 new_local 变量")
    
    return locals()

modification_result = modification_limitation_demo()

## 2. 性能考虑
print("\n2. 性能考虑:")

import time

def performance_comparison():
    """性能比较"""
    test_var1 = "测试变量 1"
    test_var2 = "测试变量 2"
    test_var3 = "测试变量 3"
    
    iterations = 100000
    
#    # 直接访问变量
    start_time = time.time()
    for _ in range(iterations):
        value = test_var1
    direct_time = time.time() - start_time
    
#    # 通过 locals()访问
    start_time = time.time()
    for _ in range(iterations):
        local_dict = locals()
        value = local_dict['test_var1']
    locals_time = time.time() - start_time
    
#    # 缓存 locals()后访问
    local_dict = locals()
    start_time = time.time()
    for _ in range(iterations):
        value = local_dict['test_var1']
    cached_locals_time = time.time() - start_time
    
    print(f"  性能比较 ({iterations} 次迭代):")
    print(f"    直接访问: {direct_time:.4f}秒")
    print(f"    locals()访问: {locals_time:.4f}秒 (慢 {locals_time/direct_time:.1f}倍)")
    print(f"    缓存 locals()访问: {cached_locals_time:.4f}秒 (慢 {cached_locals_time/direct_time:.1f}倍)")

performance_comparison()

## 3. 作用域陷阱
print("\n3. 作用域陷阱:")

def scope_trap_demo():
    """作用域陷阱演示"""
    
    def outer_function():
        outer_var = "外层变量"
        
        def inner_function():
            inner_var = "内层变量"
            
            print(f"  内层函数的 locals():")
            inner_locals = locals()
            for name, value in inner_locals.items():
                print(f"    {name}: {value}")
            
#            # 尝试访问外层变量
            print(f"  外层变量在内层 locals()中: {'outer_var' in inner_locals}")
            
#            # 但可以直接访问(闭包)
            print(f"  直接访问外层变量: {outer_var}")
            
            return inner_locals
        
        print(f"  外层函数的 locals():")
        outer_locals = locals()
        for name, value in outer_locals.items():
            if not callable(value):
                print(f"    {name}: {value}")
        
        return inner_function()
    
    return outer_function()

scope_result = scope_trap_demo()

## 4. 最佳实践
print("\n4. 最佳实践:")

class LocalsBestPractices:
    """locals()最佳实践"""
    
    @staticmethod
    def safe_locals_access(var_name: str, default=None):
        """安全的 locals()访问"""
        frame = inspect.currentframe().f_back
        try:
            return frame.f_locals.get(var_name, default)
        finally:
            del frame
    
    @staticmethod
    def locals_snapshot():
        """创建 locals()快照"""
        frame = inspect.currentframe().f_back
        try:
            return frame.f_locals.copy()
        finally:
            del frame
    
    @staticmethod
    def filter_locals(exclude_private=True, exclude_functions=True):
        """过滤 locals()内容"""
        frame = inspect.currentframe().f_back
        try:
            local_vars = frame.f_locals.copy()
            
            filtered = {}
            for name, value in local_vars.items():
#                # 排除私有变量
                if exclude_private and name.startswith('_'):
                    continue
                
#                # 排除函数
                if exclude_functions and callable(value):
                    continue
                
                filtered[name] = value
            
            return filtered
        finally:
            del frame
    
    @staticmethod
    def debug_locals_info():
        """调试 locals()信息"""
        frame = inspect.currentframe().f_back
        try:
            local_vars = frame.f_locals
            
            info = {
                'function_name': frame.f_code.co_name,
                'filename': frame.f_code.co_filename,
                'line_number': frame.f_lineno,
                'variable_count': len(local_vars),
                'variable_types': {}
            }
            
#            # 统计变量类型
            for value in local_vars.values():
                type_name = type(value).__name__
                info['variable_types'][type_name] = info['variable_types'].get(type_name, 0) + 1
            
            return info
        finally:
            del frame

## 测试最佳实践
def test_best_practices():
    """测试最佳实践"""
    test_var1 = "测试值 1"
    test_var2 = [1, 2, 3]
    _private_var = "私有变量"
    
    def local_function():
        return "局部函数"
    
    print(f"  安全访问测试:")
    value = LocalsBestPractices.safe_locals_access('test_var1', 'default')
    print(f"    test_var1: {value}")
    
    value = LocalsBestPractices.safe_locals_access('nonexistent', 'default')
    print(f"    nonexistent: {value}")
    
    print(f"\n  快照测试:")
    snapshot = LocalsBestPractices.locals_snapshot()
    print(f"    快照变量数量: {len(snapshot)}")
    
    print(f"\n  过滤测试:")
    filtered = LocalsBestPractices.filter_locals()
    print(f"    过滤后变量: {list(filtered.keys())}")
    
    print(f"\n  调试信息:")
    debug_info = LocalsBestPractices.debug_locals_info()
    for key, value in debug_info.items():
        print(f"    {key}: {value}")

test_best_practices()

## 5. 与 globals()的比较
print("\n5. 与 globals()的比较:")

global_comparison_var = "全局比较变量"

def compare_globals_locals():
    """比较 globals()和 locals()"""
    local_comparison_var = "局部比较变量"
    
    print(f"  函数中的比较:")
    print(f"    locals() == globals(): {locals() == globals()}")
    print(f"    len(locals()): {len(locals())}")
    print(f"    len(globals()): {len(globals())}")
    
    print(f"\n  变量位置:")
    print(f"    'local_comparison_var' in locals(): {'local_comparison_var' in locals()}")
    print(f"    'local_comparison_var' in globals(): {'local_comparison_var' in globals()}")
    print(f"    'global_comparison_var' in locals(): {'global_comparison_var' in locals()}")
    print(f"    'global_comparison_var' in globals(): {'global_comparison_var' in globals()}")
    
#    # 在模块级别的比较
    return locals(), globals()

func_locals, func_globals = compare_globals_locals()

print(f"\n  模块级别的比较:")
print(f"    locals() is globals(): {locals() is globals()}")
print(f"    id(locals()): {id(locals())}")
print(f"    id(globals()): {id(globals())}")

🔗 相关函数和模块

内置函数

  • globals() - 返回全局命名空间字典
  • vars() - 返回对象的属性字典
  • dir() - 列出对象的属性名
  • hasattr() - 检查对象是否有指定属性
  • getattr() - 获取对象属性值
  • setattr() - 设置对象属性值
  • delattr() - 删除对象属性

标准库模块

  • inspect - 对象检查和内省
  • types - 动态类型创建和检查
  • sys - 系统相关参数和函数
  • traceback - 异常跟踪
  • frame - 帧对象操作

第三方库

  • varname - 获取变量名
  • executing - 获取执行上下文
  • stack_data - 栈数据分析

📚 扩展阅读

🏷️ 标签

命名空间 局部变量 作用域 变量管理 调试工具 内省 函数检查 动态访问

作者: Python 文档工程师

版本: 1.0

讨论与反馈

欢迎在下方留言讨论,分享你的学习心得或提出问题。评论基于GitHub Issues,需要GitHub账号。