通过装饰器改变局部变量的范围?

时间:2013-11-01 16:59:18

标签: python global-variables python-decorators

我有一个设置name变量但在第一行没有global name的方法,它使用本地name变量,因此它永远不会更改全局name 1}}变量。 有没有办法通过装饰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

5 个答案:

答案 0 :(得分:2)

不,除非装饰器获取函数的代码(来自函数的代码对象的字节码,或使用inspect的源代码),否则更改它,从更改的代码创建新的代码对象并用该代码替换函数的代码。当然,这是非常不可靠,黑客,具体实施和黑暗魔法。只需添加global name(或完全删除全局变量)。

答案 1 :(得分:2)

简短的回答是:不。

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

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

答案 2 :(得分:0)

name = "John" #global name

和set_name()中的名称:

name = "Sara" #local name

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

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

答案 3 :(得分:0)

定义一个包裹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)和函数({{1} ,set_name)对其进行操作。

答案 4 :(得分:0)

不确定,为什么要尝试装饰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