如何在python函数中访问所有全局变量?

时间:2013-04-01 17:32:33

标签: python shelve

我正在尝试模仿matlab加载并保存函数。我正在关注这个主题:Shelve Code gives KeyError

很聪明。但是,如果我在单独的模块中编写该代码,并尝试导入该模块并撤销该函数,则无法获取全局变量。

具体来说,我写了一个happy.py并且里面有函数:

def save(filename='tmp',globals_=None):
    if globals_ is None:
        globals_ = globals()

    globals()
    import shelve
    my_shelf = shelve.open(filename, 'n')
    for key, value in globals_.items():
        if not key.startswith('__'):
            try:
                my_shelf[key] = value
            except Exception:
                print('ERROR shelving: "%s"' % key)
            else:
                print('shelved: "%s"' % key)
    my_shelf.close()

def load(filename='tmp',globals_=None):
    import shelve
    my_shelf = shelve.open(filename)
    for key in my_shelf:
        globals()[key]=my_shelf[key]
    my_shelf.close()

当我尝试

a = 1
b = 2
happy.save()

它不会给出a和b。

这是因为global()不会给模块外的对象吗?我怎么能做我想做的事呢?

非常感谢。

3 个答案:

答案 0 :(得分:0)

您可以使用inspect查看堆栈。我已经定义的这个愚蠢的(命名不佳的函数)似乎可以很好地从调用命名空间中获取全局变量,尽管我还没有对它进行过广泛的测试。我也不确定它是否适用于不同的python实现。 (我提到这一点是因为inspect.currentframe函数肯定是依赖于实现的)。它似乎与Cpython一起工作得很好。

import inspect
def save(globals=None):
    if globals is None:
        frames = inspect.stack()
        caller_frame = frames[-1][0]
        globals = dict((k,v) for (k,v) in caller_frame.f_globals.items() if not k.startswith('__'))
    return globals


if __name__ == "__main__":
    a = 1
    b = 2
    print save()

答案 1 :(得分:0)

将此代码粘贴到控制台时,我的代码没有问题:

>>> def save(filename='tmp',globals_=None):
...     import shelve
...     globals_ = globals_ or globals()
...     my_shelf=  shelve.open(filename, 'n')
...     for key, value in globals_.items():
...         if not key.startswith('__'):
...             try:
...                 my_shelf[key] = value
...             except Exception:
...                 print('ERROR shelving: "%s"' % key)
...             else:
...                 print('shelved: "%s"' % key)
...     my_shelf.close()
... 
>>> def load(filename='tmp',globals_=None):
...     import shelve
...     my_shelf = shelve.open(filename)
...     for key in my_shelf:
...         globals()[key]=my_shelf[key]
...     my_shelf.close()
... 
>>> a, b = 1, 2
>>> save()
shelved: "load"
shelved: "a"
shelved: "b"
shelved: "save"

然后:

>>> def save(filename='tmp',globals_=None):
...     import shelve
...     globals_ = globals_ or globals()
...     my_shelf=  shelve.open(filename, 'n')
...     for key, value in globals_.items():
...         if not key.startswith('__'):
...             try:
...                 my_shelf[key] = value
...             except Exception:
...                 print('ERROR shelving: "%s"' % key)
...             else:
...                 print('shelved: "%s"' % key)
...     my_shelf.close()
... 
>>> def load(filename='tmp',globals_=None):
...     import shelve
...     my_shelf = shelve.open(filename)
...     for key in my_shelf:
...         globals()[key]=my_shelf[key]
...     my_shelf.close()
... 
>>> load()
>>> a, b
(1, 2)

但是当你将它用作模块时有点奇怪:

>>> from happy import *
>>> a, b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> load()
>>> a, b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> happy.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'happy' is not defined
>>> from happy import *
>>> a, b
(1, 2)

这里有足够的解决方法吗?

答案 2 :(得分:0)

以下内容将作为一个单独的模块使用:

import shelve
import sys
import types

EXCLUDED_TYPES = set([types.ModuleType])  # everything can't be shelved

def save(filename='tmp', globals_=None):
    if globals_ is None:
        globals_ = sys._getframe(1).f_globals  # caller's globals

    my_shelf = shelve.open(filename, 'n')
    for key, value in globals_.items():
        if not key.startswith('__') and type(value) not in EXCLUDED_TYPES:
            try:
                my_shelf[key] = value
            except Exception as e:
                print('ERROR shelving: "%s"' % key, 'Exception:', e)
            else:
                print('shelved: "%s"' % key)
    my_shelf.close()

def load(filename='tmp', globals_=None):
    if globals_ is None:
        globals_ = sys._getframe(1).f_globals  # caller's globals

    my_shelf = shelve.open(filename)
    for key in my_shelf:
        globals_[key]=my_shelf[key]
        #print('unshelved: "%s"' % key)
    my_shelf.close()

一般来说,我认为创建这样的变量的函数不是一个好主意。另请注意,load()可能会静默更改调用方命名空间中的现有值。

您无法轻松保存所有全局命名空间,因为除了__main__之外,还有一个与加载的每个模块相关联的命名空间。如果您真的想这样做,可以通过迭代sys.modules的内容来实现。