在调用函数和调用函数之间共享Python范围

时间:2013-02-04 17:27:44

标签: python scope

Python中是否有办法管理范围,以便调用函数中的变量在被调用函数中可见?我想要类似下面的内容

z = 1

def a():
    z = z * 2
    print z

def b():
    z = z + 1
    print z
    a()
    print z

b()

我想获得以下输出

2
4
2

这个问题的真正解决方案就是将z作为变量传递。我不想这样做。

我拥有庞大而复杂的代码库,拥有各种专业水平的用户。他们目前接受过传递一个变量的训练,现在我必须添加另一个变量。我不相信他们通过所有函数调用始终传递第二个变量,所以我正在寻找维护接口的替代方案。这是不可能的。

5 个答案:

答案 0 :(得分:7)

我认为这就是你要找的东西。如果您控制内部函数,并且您正在寻找的变量已经在调用链中的某个范围内,但您不希望您的用户必须在调用本身中包含该变量。您显然不需要global关键字,因为您不希望内部分配影响外部范围。

使用inspect模块可以访问调用上下文。 (但是,请注意它有点脆弱。你应该只使用CPython无螺纹。)

import inspect

def calling_scope_variable(name):
  frame = inspect.stack()[1][0]
  while name not in frame.f_locals:
    frame = frame.f_back
    if frame is None:
      return None
  return frame.f_locals[name]

z = 1

def a():
  z = calling_scope_variable('z')
  z = z * 2
  print z

def b():
  z = calling_scope_variable('z')
  z = z + 1
  print z
  a()
  print z

b()

这确实给出了正确答案:

2
4
2

答案 1 :(得分:5)

这可能是课程的正确位置:

class MyClass(object):
    def __init__(self, z):
        self.z = 1

    def a(self):
        self.z = self.z * 2
        print self.z

    def b():
        self.z = self.z + 1
        print self.z
        self.a()
        print self.z

您可以使用全局变量获得相同的效果,但我建议您创建自己的独立命名空间(例如使用类)并将其用于范围。

答案 2 :(得分:2)

一般来说,最好的解决方案只是传递价值 - 这将更加可预测和自然,更易于使用和调试:

def a(z):
    z = z * 2
    print z

def b():
    global z
    z = z + 1
    print z
    a(z)
    print z

b()

您可以在a()中定义b()并执行类似操作:

def b():
    global z
    z = z + 1
    print z
    def a():
        z = z * 2
        print z
    a()
    print z

但是,这并不是最佳选择。

答案 3 :(得分:2)

我不太明白你想要达到的目标,但这会打印2,4,2:

z = 1

def a():
    global z
    y = z * 2
    print y

def b():
    global z
    z = z + 1
    print z
    a()
    print z

b()

答案 4 :(得分:2)

这有点难看,但它避免使用全局变量,我测试了它并且它有效。使用找到的here选定答案中的代码,函数getSetZ()有一个“静态”变量,可用于存储传递给它的值,然后在调用函数时检索None作为参数。某些限制是它假定None不是z的可能值,并且您不使用线程。您只需记得在每次调用希望调用函数getSetZ()可用的函数之前调用z,并从getSetZ()中获取值并将其放入在该函数的局部变量中。

def getSetZ(newZ):
    if newZ is not None:
        getSetZ.z = newZ
    else:
        return getSetZ.z

def a():
    z = getSetZ(None)
    z = z * 2
    print z

def b():
    z = getSetZ(None)
    z = z + 1
    print z
    getSetZ(z)
    a()
    print z

getSetZ.z = 0
getSetZ(1)
b()

我希望这会有所帮助。