12

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 作为变量传递。我不想这样做。

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

4

5 回答 5

13

我想这就是你要找的。如果您控制内部函数,并且您要查找的变量已经在调用链的某个范围内,但您不希望您的用户必须在调用本身中包含该变量。您显然不想要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
于 2013-02-04T19:40:38.610 回答
6

这可能是上课的好地方:

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

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

于 2013-02-04T17:40:09.907 回答
3

这有点难看,但它避免使用全局变量,我对其进行了测试并且它可以工作。使用此处找到的所选答案中的代码,该函数getSetZ()具有一个“静态”变量,可用于存储传递给它的值,然后在调用函数时将其检索None为参数。某些限制是它假定Nonez 不是可能的值,并且您不使用线程。您只需要记住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()

我希望这有帮助。

于 2013-02-04T18:40:26.973 回答
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

然而,这并不是最理想的。

于 2013-02-04T17:29:06.387 回答
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()
于 2013-02-04T18:25:08.640 回答