我可以使用装饰器来改变Python中函数的局部范围吗? [英] Can I use a decorator to mutate the local scope of a function in Python?

查看:119
本文介绍了我可以使用装饰器来改变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的答案


  1. 不要这样做。

  2. 严重的是,不要做这个。 Lisp和Ruby是用于编写自己的自定义语法的更合适的语言。使用其中之一。或者找到一种更干净的方法

  3. 如果必须的话,您需要动态作用域变量,而不是词法作用域变量。

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:

http://codepad.org/6vAY8Leh

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆