识别变量是调用方作用域中的字符串列表

时间:2018-08-23 13:47:36

标签: python module jupyter-notebook ipywidgets

我想识别出用户在其交互式shell中定义的所有字符串列表。

def lists_of_strings():
    d = dict(globals(), **locals())
    d = {k:v for (k, v) in d.items() if not k.startswith("_") and k != 'In'}
    res = {}
    for k, v in d.items():
        if isinstance(v, list):
            if all(map(lambda x: isinstance(x, str), v)):
                res[k] = v
    return res

当我在当前shell中定义此函数时,它会起作用:

>>> lists_of_strings()
{}
>>> mylist = ["a", "b"]
>>> lists_of_strings()
{"mylist": ["a", "b"]}

现在,如果我将此功能移至模块mymodule中并导入:

>>> from mymodule import lists_of_strings
>>> lists_of_strings()
{}
>>> mylist = ["a", "b"]
>>> lists_of_strings()
{}

该函数总是返回一个空字典。为什么,更重要的是,我可以解决它吗?

某些情况:我正在尝试在模块中编写一个帮助程序,以标识用户在当前jupyter笔记本中定义的合适变量。我的目标是询问用户是否要将这些变量用作某些预定义函数的参数。

1 个答案:

答案 0 :(得分:1)

Python的globals内置函数返回包含当前模块的全局变量的字典。这是一个非常不错的功能,因为“全局”变量不在进程范围内,并且在模块(因此在文件)范围内-允许每个模块用作名称空间。为避免大型系统中的名称冲突,这简化了很多工作(如果使用第三方组件,则避免这种情况。)

但是,是的,有一种方法可以访问另一个运行上下文的全局变量。所有Python代码都在frame对象的上下文中运行-它保留了对当前使用的实际字节码,局部变量和全局变量的引用。框架对象的f_globals属性实际上与内置globals返回的字典相同。

因此,您要做的就是获取对调用函数的框架对象的引用-这可以通过采用当前框架的.f_back属性来实现。

这意味着,如果将其更改为以下功能,则该函数将跨模块(以及在导入时)起作用:

import sys

def lists_of_strings():
    caller_frame = sys._getframe().f_back
    d = dict(caller_frame.f_globals, **caller_frame.f_locals)
    d = {k:v for (k, v) in d.items() if not k.startswith("_") and k != 'In'}
    res = {}
    for k, v in d.items():
        if isinstance(v, list):
            if all(map(lambda x: isinstance(x, str), v)):
                res[k] = v
    return res

也就是说,必须注意并非所有代码都需要使用框架。如果您只想知道已知模块中的 global 变量,则可以使用该模块的__dict__属性:

import math
print (math.__dict__)