<p>这是可以做到的,但我警告你-<strong>这不会很好</strong>!您可以做的是捕获函数中的调用方框架,然后提取调用行,解析它并提取传递的参数,然后将它们与函数签名进行比较并创建参数映射,然后调用函数,并且在函数完成本地堆栈中的更改后,将其与映射的调用方框架进行比较并更新变化。如果你想看看它有多傻,这里有一个演示:</p>
<pre><code># HERE BE DRAGONS
# No, really, here be dragons, this is strictly for demonstration purposes!!!
# Whenever you use this in code a sweet little pixie is brutally killed!
import ast
import inspect
import sys
def here_be_dragons(funct): # create a decorator so we can, hm, enhance 'any' function
def wrapper(*args, **kwargs):
caller = inspect.getouterframes(inspect.currentframe())[1] # pick up the caller
parsed = ast.parse(caller[4][0], mode="single") # parse the calling line
arg_map = {} # a map for our tracked args to establish global <=> local link
for node in ast.walk(parsed): # traverse the parsed code...
# and look for a call to our wrapped function
if isinstance(node, ast.Call) and node.func.id == funct.__name__:
# loop through all positional arguments of the wrapped function
for pos, var in enumerate(funct.func_code.co_varnames):
try: # and try to find them in the captured call
if isinstance(node.args[pos], ast.Name): # named argument!
arg_map[var] = node.args[pos].id # add to our map
except IndexError:
break # no more passed arguments
break # no need for further walking through the ast tree
def trace(frame, evt, arg): # a function to capture the wrapped locals
if evt == "return": # we're only interested in our function return
for arg in arg_map: # time to update our caller frame
caller[0].f_locals[arg_map[arg]] = frame.f_locals.get(arg, None)
profile = sys.getprofile() # in case something else is doing profiling
sys.setprofile(trace) # turn on profiling of the wrapped function
try:
return funct(*args, **kwargs)
finally:
sys.setprofile(profile) # reset our profiling
return wrapper
</code></pre>
<p>现在你可以很容易地装饰你的功能,使它能够执行这种不虔诚的滑稽:</p>
<pre><code># Zap, there goes a pixie... Poor, poor, pixie. It will be missed.
@here_be_dragons
def your_function(in1, in2):
in1 = in1 + 1
in2 = in2 + 1
</code></pre>
<p>现在,演示:</p>
<pre><code>a = 1
b = 2
c = 3
d = 4
# Now is the time to play and sing along: Queen - A Kind Of Magic...
your_function(a, b) # bam, two pixies down... don't you have mercy?
your_function(c, d) # now you're turning into a serial pixie killer...
print(a, b, c, d) # Woooo! You made it! At the expense of only three pixie lives. Savage!
# prints: (2, 3, 4, 5)
</code></pre>
<p>显然,这只适用于带有位置参数的非嵌套函数,并且只有当您传递简单的本地参数时,才可以随意进入处理关键字参数、不同堆栈、返回/包装/链接调用和其他诡计(如果您喜欢的话)的兔子洞。</p>
<p>或者,您知道,您可以使用为此而发明的结构,比如全局变量、类,甚至是封闭的可变对象。别再杀小精灵了。</p>