【问题标题】:Losing variable scope inside a Python decorator在 Python 装饰器中丢失变量范围
【发布时间】:2011-07-03 01:51:49
【问题描述】:

这个简单的装饰器按预期工作:

def protect(*permissions):
    def outer(f):
        def inner(*args):
            print permissions[0]
            return f(*args)  
        return inner  
    return outer

@protect('protected')
def func(var):
    return var

print func('something')

输出是:

protected
something

超越 Python shell 并在我的项目的更大范围内使用装饰器,发生了一些奇怪的事情:在 inner 函数内部,permissions 没有定义。

我想一定有一些 Python 变量范围/装饰器的细微之处我不知道这可能会导致这种情况。任何见解都值得赞赏。

【问题讨论】:

  • 好吧,我们需要不起作用的代码;)它的输出(或者确切地说,确切的错误消息)也会有所帮助。
  • 当我试图访问权限的值时,这是一个 NameError。我现在正在挠头,b/c 一切正常。一定是装饰师之外的问题。抱歉问了一个不好的问题。

标签: python scope decorator


【解决方案1】:

在我的脑海中,我可以弄清楚发生了什么 - 让我试着把它拼出来:

这与 Python 没有“感知”“权限”变量存在于“内部”函数之外的范围有关 - 因为当“内部”本身被定义时,“权限”早就在 '最外的保护范围。因此,在编译inner 时,变量被视为全局变量。 (这就是为什么需要 exact 错误消息的原因 - NameErrors 可以用于定义之前使用的局部变量,也可以用于不存在的全局变量 - 在这种情况下,确切的消息会说明很多)

换句话说,您很可能遇到了实现错误 - 请尝试公开导致问题的最少代码量以及您使用的确切 python 版本。如果可能,请尝试为您提供最新的微版本 - 十个,是时候在 bugs.python.org 上打开一个问题了

我看到了两种解决方法——第一种是可以确认我的诊断的 hack——并且可能根本不起作用:在outer 函数之外对permissions 变量进行读取访问inner的主体:这应该使解释器“感知”它作为外部的非局部变量,并将其传播到内部。

另一种解决方法更可靠和一致 - 在这种情况下,yu 的代码样式可能更好:在这种情况下使用类作为装饰器,而不是依赖多个嵌套函数及其闭包。

上面的sn-p可以改写为:

class Protect(object):
    def __init__(self, *permissions):
        self.permissions = permissions
    def __call__(self, f):
        def inner(*args):
            print self.permissions[0]
            return f(*args)  
        return inner  

@Protect('protected')
def func(var):
    return var

print func('something')

此代码不依赖嵌套闭包,因此避免了您遇到的错误。此外,它遵循“平面优于嵌套”和“显式优于隐式”的编码准则。

但是,如果不是在 python.org 上打开问题,请向我们提供实际触发此行为的版本和代码,帮助大家追踪此错误

【讨论】:

  • 哎呀我现在“工作”呢?没有 python 错误它们 - 无论哪种方式,考虑使用这个扁平版本的装饰器 - 更容易跟踪它的错误。
【解决方案2】:

我曾经遇到过这个问题,这是因为您无法设置放入闭包中的变量。不知道你是否是这种情况,但很高兴知道。

【讨论】:

  • 不要认为这适用于这里,因为我不想设置它。只需访问它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-18
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 2021-11-08
  • 2013-07-25
相关资源
最近更新 更多