【问题标题】:Change scope of local variable by decorators?通过装饰器更改局部变量的范围?
【发布时间】:2013-11-01 16:59:18
【问题描述】:

我有一个设置name 变量的方法,但它的第一行没有global name,它使用本地name 变量,因此它永远不会更改全局name 变量。 有什么办法可以通过装饰set_name 强制它使用全局name

name = "John"

def set_name():
    name = "Sara"

def print_name():
    global name
    print(name)

def decorator(func):
    def wrapper(*args, **kwargs):
        ## Problem:
        # Force set_name to use global 'name'
        func(*args, **kwargs)

    return wrapper

print_name()
#Output: John

decorator(set_name)()

print_name()
# Prints John, but I want to prints Sara

【问题讨论】:

  • 也许有某种深层次的 Python 魔法可以做到这一点,但简短的回答是否定的。装饰器不会改变它们包装的函数。
  • 我不认为你能做到这一点......我很难理解你为什么要这样做
  • 您似乎使用set_nameprint_name 方法定义了一个类,而没有实际声明一个类。

标签: python global-variables python-decorators


【解决方案1】:

不,除非装饰器获取函数的代码(来自函数代码对象的字节码,或使用inspect 的源代码),更改它,从更改的代码创建一个新的代码对象并用它替换函数的代码。当然,这是非常不可靠的、骇人听闻的、特定于实现的和深奥的黑魔法。只需添加global name(或完全删除全局变量)。

【讨论】:

    【解决方案2】:

    简短的回答是:不。

    有点扩展的答案:不,不是以便携的方式。从技术上讲,您可以使用 CPython 字节码,但是

    • 不会在任何其他解释器上运行,
    • 没有人能够理解该代码,
    • 头痛不值得。

    【讨论】:

      【解决方案3】:
      name = "John" #global name
      

      和 set_name() 中的名称:

      name = "Sara" #local name
      

      要在函数set_name() 中使用全局名称,请执行以下操作:

      def set_name():
         global name
         name = "Sara"
      

      【讨论】:

      • 谢谢,但我的意思是装饰。
      【解决方案4】:

      定义一个包装name的类:

      class Person(object):
          def __init__(self):
              self.name = "John"
      
          def set_name(self):
              self.name = "Sara"
      
          def print_name(self):
              print(name)
      
      p = Person()
      p.print_name()   # Prints John
      p.set_name()     # Changes name to Sara
      p.print_name()   # Prints Sara
      

      像这样硬编码其属性值的类当然有点傻,但这说明了类的目的:封装数据(name)和函数(set_name,@987654325 @) 对其进行操作。

      【讨论】:

        【解决方案5】:

        不确定,为什么要装饰 setter。

        您可以这样做,但我不建议将其作为通常的编码风格:

        name = "John"
        
        def print_name():
            print name
        
        def decorator(func, tmp_name):
            def wrapper(*args, **kwargs):
                global name
                old_name = name
                name = tmp_name
                func(*args, **kwargs)
                name = old_name
            return wrapper
        
        print_name()
        decorator(print_name, 'Sarah')()
        print_name()
        

        输出:

        John
        Sarah
        John
        

        【讨论】:

          猜你喜欢
          • 2012-08-18
          • 1970-01-01
          • 1970-01-01
          • 2013-03-20
          • 2011-02-12
          • 1970-01-01
          • 2011-07-03
          • 2014-03-02
          • 1970-01-01
          相关资源
          最近更新 更多