封装内存对象列表的Python函数返回空列表,直接运行代码正常的原因
问题描述
将一段用于获取并排序内存中对象及其占用大小的代码封装为memory_obj_list函数后,调用函数返回空列表,但直接运行原代码功能正常,请问差异原因是什么?
原代码(直接运行正常)
import sys # 这些是IPython环境下常见的内置对象,包括你正在创建的这个变量 ipython_vars = ['In', 'Out', 'exit', 'quit', 'get_ipython', 'ipython_vars'] # 获取对象及其占用大小的排序后的列表 sorted([(x, sys.getsizeof(globals().get(x))/1e6) for x in dir() if not x.startswith('_') and x not in sys.modules and x not in ipython_vars], key=lambda x: x[1], reverse=True)
封装后的函数(调用返回空列表)
def memory_obj_list(): import sys # 这些是IPython环境下常见的内置对象,包括你正在创建的这个变量 ipython_vars = ['In', 'Out', 'exit', 'quit', 'get_ipython', 'ipython_vars'] # 获取对象及其占用大小的排序后的列表 a = sorted([(x, sys.getsizeof(globals().get(x))/1e6) for x in dir() if not x.startswith('_') and x not in sys.modules and x not in ipython_vars], key=lambda x: x[1], reverse=True) return(a)
调用方式
memory_obj_list()
原因分析
核心差异在于作用域的不同:
- 原代码在全局作用域运行,
dir()会列出当前全局环境下的所有变量名,globals()获取的是全局命名空间字典,因此能捕获到你在全局定义的各种对象。 - 封装成函数后,函数内部的
dir()(不带参数)默认返回的是函数局部作用域的变量名,也就是函数内定义的sys、ipython_vars、a这些。而过滤条件会排除掉模块(sys属于sys.modules)、ipython_vars列表里的名字,剩下的符合条件的变量名为空,最终返回空列表。
修复方案
修改函数,明确获取全局作用域的变量名和命名空间,替换掉函数内的局部dir()调用:
def memory_obj_list(): import sys # 这些是IPython环境下常见的内置对象,包括你正在创建的这个变量 ipython_vars = ['In', 'Out', 'exit', 'quit', 'get_ipython', 'ipython_vars'] # 直接获取全局命名空间字典 global_ns = globals() # 遍历全局命名空间的键,而非函数局部的变量名 result = sorted( [(name, sys.getsizeof(global_ns[name])/1e6) for name in global_ns if not name.startswith('_') and name not in sys.modules and name not in ipython_vars], key=lambda x: x[1], reverse=True ) return result
这样函数就能正确捕获全局作用域的对象,和原代码运行效果一致。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

