identify global symbols in lambda expressions
<p>I need to get the list of names of all symbols which I must have available in order to evaluate or execute a piece of code. I tried to use <code>symtable</code> module but it seems that it does not handle properly lambdas and inner functions (<code>def</code>s inside other code). Consider this:</p>

<pre><code>import symtable
symtable.symtable("x+y", '&lt;string&gt;', 'exec').get_symbols()
</code></pre>

<p>I get this: <code>[&lt;symbol 'y'&gt;, &lt;symbol 'x'&gt;]</code> which is exactly what I expect.</p>

<p>but when I write this:</p>

<pre><code>symtable.symtable("z=lambda x: x+y; z(10)", '&lt;string&gt;', 'exec').get_symbols()
</code></pre>

<p>the results is: <code>[&lt;symbol 'z'&gt;]</code> and I have no info about <code>x</code> (never mind, it is a local variable) nor <code>y</code> (which is global and this is what I need).</p>

<p>But when I try to evaluate this with <code>exec("z=lambda x: x+y; z(10)")</code> the value of <code>y</code> is missing. Is there a way I can identify the names of all symbols which must be supplied to an expression or code so that it can be evaluated/executed?</p>

<p>Without much ado... I need to look into child symbol tables. Recursion is the tool of choice:</p>

<pre><code>import symtable

def find_global_symbols(table):
    symbols = set()
    for t in table.get_children():
        symbols |= find_global_symbols(t)
    symbols |= set(s.get_name() for s in table.get_symbols() if s.is_global())
    return symbols

table = symtable.symtable("z=lambda x: x+y; z(10)", '&lt;string&gt;', 'exec')
global_symbols = find_global_symbols(table)
</code></pre>

<p>Which gives me <code>y</code> as the answer. This is what I need. Now I know that I have to supply the value of <code>y</code> to be able to execute the code in question.</p>

<p>UPDATE: actually there is a possible improvement if I take into account the names which are imported in each scope</p>

<pre><code>def find_global_symbols(table, imports):
    imports = imports | set(s.get_name() for s in table.get_symbols() if s.is_imported())
    symbols = set()
    for s in table.get_symbols():
        if s.is_global() and s.get_name() not in imports:
            symbols.add(s.get_name())
    for t in table.get_children():
        symbols |= find_global_symbols(t, imports)
    return symbols

table = symtable.symtable("z=lambda x: x+y; z(10)", '&lt;string&gt;', 'exec')
global_symbols = find_global_symbols(table, set())
</code></pre>

python lambda