Как получить доступ ко всем глобальным переменным в функции 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)
Здесь достаточно для вас, чтобы обойти?