我可以使用装饰器来改变Python中函数的局部范围吗? [英] Can I use a decorator to mutate the local scope of a function in Python?
问题描述
有没有办法编写一个装饰器,使下面的方法起作用?
Is there any way of writing a decorator such that the following would work?
assert 'z' not in globals()
@my_decorator
def func(x, y):
print z
编辑:从anwser移走
moved from anwser
回答蛇麻草的为什么?:语法糖
In answer to hop's "why?": syntax sugar / DRY.
这与缓存无关,而是根据x&的值计算z(以及z1,z2,z3,...)。 y。
It's not about caching, it's about calculating z (and z1, z2, z3, ...) based upon the values of x & y.
我有很多函数可以做相关的事情,而我不想写
I have lots of functions which do related things, and I don't want to do have to write
z1, z2, z3=calculate_from(x, y)
在每个函数的开头-我会在某处弄错。如果这是c,我将使用cpp进行此操作(如果这是lisp,我将使用宏进行此操作...),但我想查看装饰器是否可以执行相同的操作。
at the beginning of every single function - I'll get it wrong somewhere. If this were c I'd do this with cpp (if this were lisp, I'd do this with macros ...), but I wanted to see if decorators could do the same thing.
如果有帮助,我几乎可以肯定将装饰器称为 precalculate_z,并且肯定不会成为任何公共API的一部分。
If it helps, I'd almost certainly call the decorator "precalculate_z", and it certainly wouldn't be part of any public API.
使用类基础结构也可能会得到类似的效果,但是我想看看它是否可用于原始函数。
I could probably get a similar effect from using the class infrastructure as well, but I wanted to see if it was doable with raw functions.
推荐答案
呼应Hop的答案
- 不要这样做。
- 严重的是,不要做这个。 Lisp和Ruby是用于编写自己的自定义语法的更合适的语言。使用其中之一。或者找到一种更干净的方法
- 如果必须的话,您需要动态作用域变量,而不是词法作用域变量。
Python没有动态作用域变量,但是您可以模拟它。这是一个通过创建全局绑定来模拟它的示例,但是在退出时恢复了先前的值:
Python doesn't have dynamically scoped variables, but you can simulate it. Here's an example that simulates it by creating a global binding, but restores the previous value on exit:
def adds_dynamic_z_decorator(f):
def replacement(*arg,**karg):
# create a new 'z' binding in globals, saving previous
if 'z' in globals():
oldZ = (globals()['z'],)
else:
oldZ = None
try:
globals()['z'] = None
#invoke the original function
res = f(*arg, **karg)
finally:
#restore any old bindings
if oldZ:
globals()['z'] = oldZ[0]
else:
del(globals()['z'])
return res
return replacement
@adds_dynamic_z_decorator
def func(x,y):
print z
def other_recurse(x):
global z
print 'x=%s, z=%s' %(x,z)
recurse(x+1)
print 'x=%s, z=%s' %(x,z)
@adds_dynamic_z_decorator
def recurse(x=0):
global z
z = x
if x < 3:
other_recurse(x)
print 'calling func(1,2)'
func(1,2)
print 'calling recurse()'
recurse()
我不保证其效用或完整性以上代码。实际上,我保证它 是疯狂的,除非您希望从Python同行那里获得鞭log,否则应避免使用它。
I make no warranties on the utility or sanity of the above code. Actually, I warrant that it is insane, and you should avoid using it unless you want a flogging from your Python peers.
此代码是类似于eduffy和John Montgomery的代码,但是确保创建 z并正确地像本地变量一样还原 z,例如,请注意 other_recurse如何能够看到在其中指定的 z的绑定递归的主体。
This code is similar to both eduffy's and John Montgomery's code, but ensures that 'z' is created and properly restored "like" a local variable would be -- for instance, note how 'other_recurse' is able to see the binding for 'z' specified in the body of 'recurse'.
这篇关于我可以使用装饰器来改变Python中函数的局部范围吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!