Inferring initial locals()

G

George Sakkis

I wonder if there is a (preferably not too-hackish) solution to the
following introspection problem: given a callable and a number of
positional and/or keyword arguments, infer what would be the frame's
locals() right after the function is called. For example, given:

def f(x, y=1, *a, **k):
z = x + y
w = len(a) - len (k)
return z * w

I'd like to have a function

def get_init_locals(callable, *args, **kwds):
# TODO
pass

so that:
{'a': (), 'k': {'q': -1}, 'x': 3, 'y': 1}

Any takers ?

George
 
B

bruno.desthuilliers

I wonder if there is a (preferably not too-hackish) solution to the
following introspection problem: given a callable and a number of
positional and/or keyword arguments, infer what would be the frame's
locals() right after the function is called. For example, given:

def f(x, y=1, *a, **k):
z = x + y
w = len(a) - len (k)
return z * w

I'd like to have a function

def get_init_locals(callable, *args, **kwds):
# TODO
pass

so that:


{'a': (), 'k': {}, 'x': 3, 'y': 1}

You might be intersted in the 'inspect' module.
 
G

George Sakkis

You might be intersted in the 'inspect' module.

Turns out it wasn't that hard after all; I came up with the following:

import types, inspect
from itertools import islice, izip

def localsProber(callable):
args, varargs, varkw, defaults = inspect.getargspec(callable)
if defaults is None: defaults = ()
# create a function with the same signature as the callable and
# "return locals()" for body
context = {'__builtins__': {'locals': locals}}
iterargs = iter(args)
# - first all the required args
sig_args = list(islice(iterargs, len(args)-len(defaults)))
# - then all the default args
for arg,default in izip(iterargs,defaults):
context[arg] = default
sig_args.append('%s=%s' % (arg,arg))
# - then variable positional and keyword args (if any)
if varargs: sig_args.append('*' + varargs)
if varkw: sig_args.append('**' + varkw)
name = callable.__name__
exec 'def %s(%s): return locals()' % (name, ', '.join(sig_args))
in context
prober = context[name]
if inspect.ismethod(callable): # return a method if callable is a
method
prober = types.MethodType(prober, callable.im_self,
callable.im_class)
return prober
{'a': (), 'k': {}, 'x': 3, 'y': 1}
{'a': (5,), 'k': {}, 'x': 3, 'y': 4}
{'a': (), 'k': {'q': -1}, 'x': 3, 'y': 1}


George
 
S

Scott David Daniels

George said:
Turns out it wasn't that hard after all; I came up with the following:
....

So, what should your code do about this:

def someFunction(a, b, c=43, d=14, f=12):
print locals()

import functools

a_funct = functools.partial(someFunction, d=13, c=5)
b_funct = functools.partial(a_funct, 14, d=12)
localsProber(b_funct)

My point is simply:
Introspection code is often written with a fixed idea of what other
programmers write. The others don't use introspection, the others
don't use higher order functions to build functions, ....

--Scott David Daniels
(e-mail address removed)
 
G

George Sakkis

So, what should your code do about this:

def someFunction(a, b, c=43, d=14, f=12):
print locals()

import functools

a_funct = functools.partial(someFunction, d=13, c=5)
b_funct = functools.partial(a_funct, 14, d=12)
localsProber(b_funct)

Didn't get too far :)

Traceback (most recent call last):
File "locprobe.py", line 54, in <module>
localsProber(b_funct)
File "locprobe.py", line 9, in localsProber
args, varargs, varkw, defaults = inspect.getargspec(callable)
File "C:\Python25\lib\inspect.py", line 728, in getargspec
raise TypeError('arg is not a Python function')
TypeError: arg is not a Python function

My point is simply:
Introspection code is often written with a fixed idea of what other
programmers write. The others don't use introspection, the others
don't use higher order functions to build functions, ....

Fair enough, especially since not even the standard inspect module
handles functools.partial objects. Perhaps things will improve after
2.6 with PEP 362 (Function Signature Object) in place.

What you claim about introspection code though I think holds for code
in general. There are quite often edge cases which the programmer
doesn't anticipate or care to handle. A tool that covers X% of real-
world use cases for some large X and documents the known limitations
for the rest 100-X is fine with me (e.g. the current lambda).

George
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top