Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a dict of all variables currently in scope and their values

Tags:

python

Consider this snippet:

globalVar = 25  def myfunc(paramVar):     localVar = 30     print "Vars: {globalVar}, {paramVar}, {localVar}!".format(**VARS_IN_SCOPE)  myfunc(123) 

Where VARS_IN_SCOPE is the dict I'm after that would contain globalVar, paramVar and localVar, among other things.

I'd like to basically be able to reference all the variables that are currently in scope inside the string. Hence the expected output would be:

Vars: 25, 123, 30

I can achieve this by passing **dict(globals().items() + locals().items()) to format(). Is this always correct or are there some corner cases that this expression would handle incorrectly?

Rewritten to clarify the question.

like image 293
Roman Starkov Avatar asked Jun 25 '09 00:06

Roman Starkov


People also ask

How will you get the information about all variables that are currently in scope?

You can see scopes and their variables in [[Scopes]] , even closure scopes using console. dir() . It shows you the variables in "[[Scopes]] > Closure", "[[Scopes]] > Global" and even "[[Scopes]] > Script" if the page have scripts reachable. Even with nested closures you can see the nested scopes.

Can dict list have value?

It definitely can have a list and any object as value but the dictionary cannot have a list as key because the list is mutable data structure and keys cannot be mutable else of what use are they.


2 Answers

Best way to merge two dicts as you're doing (with locals overriding globals) is dict(globals(), **locals()).

What the approach of merging globals and locals is missing is (a) builtins (I imagine that's deliberate, i.e. you don't think of builtins as "variables"... but, they COULD be, if you so choose!-), and (b) if you're in a nested function, any variables that are local to enclosing functions (no really good way to get a dict with all of those, plus -- only those explicitly accessed in the nested function, i.e. "free variables" thereof, survive as cells in a closure, anyway).

I imagine these issues are no big deal for your intended use, but you did mention "corner cases";-). If you need to cover them, there are ways to get the built-ins (that's easy) and (not so easy) all the cells (variables from enclosing functions that you explicitly mention in the nested function -- thefunction.func_code.co_freevars to get the names, thefunction.func_closure to get the cells, cell_contents on each cell to get its value). (But, remember, those will only be variables from enclosing functions that are explicitly accessed in your nested function's code!).

like image 84
Alex Martelli Avatar answered Oct 01 '22 12:10

Alex Martelli


Does this do what you intended?

d = dict(globals()) d.update(locals()) 

If I read the documentation correctly, you create a copy of the globals() dict, then you overwrite any duplicates and insert new entries from the locals() dict (since the locals() should have preference within your scope, anyway).


I haven't had any luck in getting a proper function to return the full dictionary of variables in scope of the calling function. Here's the code (I only used pprint to format the output nicely for SO):

from pprint import *  def allvars_bad():     fake_temp_var = 1     d = dict(globals())     d.update(locals())     return d  def foo_bad():     x = 5     return allvars_bad()  def foo_good():     x = 5     fake_temp_var = "good"     d = dict(globals())     d.update(locals())     return d  pprint (foo_bad(), width=50) pprint (foo_good(), width=50) 

and the output:

 {'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d316ec>,  '__builtins__': <module '__builtin__' (built-in)>,  '__doc__': None,  '__file__': 'temp.py',  '__name__': '__main__',  '__package__': None,  'allvars_bad': <function allvars_bad at 0xb7d32b1c>,  'd': <Recursion on dict with id=3084093748>,  'fake_temp_var': 1,  'foo_bad': <function foo_bad at 0xb7d329cc>,  'foo_good': <function foo_good at 0xb7d32f0c>,  'isreadable': <function isreadable at 0xb7d32c34>,  'isrecursive': <function isrecursive at 0xb7d32c6c>,  'pformat': <function pformat at 0xb7d32bc4>,  'pprint': <function pprint at 0xb7d32b8c>,  'saferepr': <function saferepr at 0xb7d32bfc>} {'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d316ec>,  '__builtins__': <module '__builtin__' (built-in)>,  '__doc__': None,  '__file__': 'temp.py',  '__name__': '__main__',  '__package__': None,  'allvars_bad': <function allvars_bad at 0xb7d32b1c>,  'd': <Recursion on dict with id=3084093884>,  'fake_temp_var': 'good',  'foo_bad': <function foo_bad at 0xb7d329cc>,  'foo_good': <function foo_good at 0xb7d32f0c>,  'isreadable': <function isreadable at 0xb7d32c34>,  'isrecursive': <function isrecursive at 0xb7d32c6c>,  'pformat': <function pformat at 0xb7d32bc4>,  'pprint': <function pprint at 0xb7d32b8c>,  'saferepr': <function saferepr at 0xb7d32bfc>,  'x': 5} 

Note that in the second output, we have overwritten fake_temp_var, and x is present; the first output only included the local vars within the scope of allvars_bad.

So if you want to access the full variable scope, you cannot put locals() inside another function.


I had suspected there was some sort of frame object, I just didn't (know where to) look for it.

This works to your spec, I believe:

def allvars_good(offset=0):     frame = sys._getframe(1+offset)     d = frame.f_globals     d.update(frame.f_locals)     return d   def foo_good2():     a = 1     b = 2     return allvars_good() 

-->

{'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d6474c>,  '__builtins__': <module '__builtin__' (built-in)>,  '__doc__': None,  '__file__': 'temp.py',  '__name__': '__main__',  '__package__': None,  'a': 1,  'allvars_bad': <function allvars_bad at 0xb7d65b54>,  'allvars_good': <function allvars_good at 0xb7d65a04>,  'b': 2,  'foo_bad': <function foo_bad at 0xb7d65f44>,  'foo_good': <function foo_good at 0xb7d65f7c>,  'foo_good2': <function foo_good2 at 0xb7d65fb4>,  'isreadable': <function isreadable at 0xb7d65c6c>,  'isrecursive': <function isrecursive at 0xb7d65ca4>,  'pformat': <function pformat at 0xb7d65bfc>,  'pprint': <function pprint at 0xb7d65bc4>,  'saferepr': <function saferepr at 0xb7d65c34>,  'sys': <module 'sys' (built-in)>} 
like image 41
Mark Rushakoff Avatar answered Oct 01 '22 13:10

Mark Rushakoff