Как получить доступ ко всем глобальным переменным в функции Python?

Я пытаюсь имитировать загрузку и сохранение функций Matlab. Я следую за этой веткой: Код полки дает 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()

это не даст сохранить а и б.

Это потому, что global() не выдаст объекты вне модуля? Как я могу делать то, что я хочу сделать тогда?

Большое спасибо.

3 ответа

Решение

Ты можешь использовать 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()

Следующее будет работать как отдельный модуль:

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__"S. Если вы действительно хотите это сделать, возможно, это можно сделать, просматривая содержимое sys.modules,

У меня нет проблем с этим кодом, когда он вставлен в консоль:

>>> 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)

Здесь достаточно для вас, чтобы обойти?

Другие вопросы по тегам