-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFreeVariableFunction.py
60 lines (51 loc) · 1.88 KB
/
FreeVariableFunction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from types import FunctionType
class FreeVariableFunction(object):
"""
A function-like object which can handle free variables
"""
usedFreeVariables = set()
def __init__(self, func):
self.func = func
self.freeVariables = {}
self.findInnerFreeVariables()
FreeVariableFunction.usedFreeVariables.update(self.freeVariables.keys())
def __call__(self,*args):
return self.func(*args)
@staticmethod
def getFreeVariables(func):
"""
extract the variable names that aren't in the global namespace
@param func:
"""
return filter(lambda n: n not in func.func_globals, func.func_code.co_names)
def updateGlobals(self, dvals={}):
"""
update the globals dictionary of each function with the values in dvals
@param dvals: dictionary of values
"""
for var,func in self.freeVariables.items():
func.func_globals[var] = dvals[var]
def argCount(self):
return self.func.func_code.co_argcount
def findInnerFreeVariables(self):
"""
create a map of free variables within each inner function of self.func
"""
def _findFunctions(func):
for fv in FreeVariableFunction.getFreeVariables(func):
self.freeVariables[fv] = func
if not func.func_closure:
return
for closure in func.func_closure:
obj = closure.cell_contents
if isinstance(obj, FunctionType):
_findFunctions(obj)
_findFunctions(self.func)
if __name__ == "__main__":
from math import sin
from superficie.plots.plot3d import func2param
par = func2param(lambda u,v: h* u + sin(v)-w)
fvf = FreeVariableFunction(par)
print fvf.freeVariables
fvf.updateGlobals({'h':1, 'w':0})
print fvf(1,1)