【问题标题】:Accessing the outer scope in Python 2.6在 Python 2.6 中访问外部作用域
【发布时间】:2023-03-08 02:55:01
【问题描述】:

说,我有一些带变量的作用域,在这个作用域中调用的函数想要改变一些不可变的变量:

定义外部(): s = 'qwerty' n = 123 调整() 定义修改(): s = 'abcd' n = 456

是否有可能以某种方式访问​​外部范围?类似于来自 Py3k 的 nonlocal 变量。

当然,在这种情况下我可以使用s,n = modify(s,n),但是如果我需要一些通用的“注入”来执行并且必须能够重新分配给任意变量怎么办?

我考虑到了性能,所以,如果可能的话,eval 和堆栈帧检查是不受欢迎的 :)


UPD:不可能。时期。但是,有一些选项如何访问外部范围内的变量:

  1. 使用全局变量。顺便说一句,func.__globals__ 是一个可变字典;)
  2. 将变量存储在 dict/class-instance/任何其他可变容器中
  3. 将变量作为参数并将它们作为元组返回:a,b,c = innerfunc(a,b,c)
  4. 注入其他函数的字节码。这可以通过byteplay python 模块实现。

【问题讨论】:

  • 这不是作用域的工作方式。您要求访问不同堆栈帧上的范围。如果作用域允许您在此处尝试的操作,那将是非常令人困惑,考虑将尾递归重写为循环。所以代码优化突然会改变程序的含义,这永远不会发生。

标签: python scope


【解决方案1】:

在函数之外定义变量并使用global 关键字。

s, n = "", 0

def outer():
    global n, s
    n = 123
    s = 'qwerty'
    modify()

def modify():
    global n, s
    s = 'abcd'
    n = 456

【讨论】:

  • and 替换为 xor 以使其正常工作。从头开始重写以获得好的建议。
  • 他的意思是“在外面定义它们,或者使用global,但不能同时使用”。
  • 如果您在全局范围内定义变量声明它们global(而不是这样做either),那么严格来说它会,工作-但这当然不是一个合适的解决方案。 (编辑:刚刚注意到我把事情搞混了......应该是“用and替换xor” - iFail)
【解决方案2】:

有时我会遇到这样的代码。嵌套函数修改可变对象而不是分配给nonlocal

def outer():
    s = [4]
    def inner():
        s[0] = 5
    inner()

【讨论】:

  • 这很有趣。丑陋但有趣。
  • 您可以键入 outer.s = 4,但这会为 outer() 函数分配一个属性。它与分配给名为 s 的局部变量不同。
【解决方案3】:

不是nonlocal 的工作方式。它不提供动态作用域(这只是一个等待发生的巨大 PITA,甚至比一般的“邪恶”功能更有用)。它只是修复了词法作用域。

无论如何,你不能做你想做的事(我会说这是一件好事)。甚至没有一个肮脏但简单的 hack(虽然我们正在这样做:这样的 hack 并不气馁,因为它们通常表现得更糟!)。忘记它并正确解决真正的问题(您没有命名,因此我们对此无话可说)。

您可以获得的最接近的方法是定义一些对象,该对象包含您想要共享的所有内容并明确传递(例如,创建一个类并使用self,如另一个答案中所建议的那样)。但这在任何地方都比较麻烦,而且仍然很麻烦(尽管比动态范围更好,因为“显式优于隐式”)。

【讨论】:

    【解决方案4】:

    您的选择是使用global 变量,

    s = None
    n = None
    
    def outer(self):
        global s
        global n
        s = 'qwerty'
        n = 123
        modify()
    
    def modify(self):
        global s
        global n
        s = 'abcd'
        n = 456
    

    或将它们定义为方法并使用类或实例变量。

    class Foo(object):
        def __init__(self):
            self.s = None
            self.n = None
    
        def outer(self):
            self.s = 'qwerty'
            self.n = 123
            self.modify()
    
        def modify(self):
            self.s = 'abcd'
            self.n = 456
    

    【讨论】:

      【解决方案5】:

      你可能也可以这样做(不是说它是对的);

      定义一个函数,该函数返回一个包含这样行的数组

      ["a = qwerty","n = 123"]
      

      然后在你需要的范围内做变量

      for row in array:
        eval(row)
      

      不过这实在是太坑爹了。

      【讨论】:

      • 我想你的意思是exec(row); eval 仅用于表达式
      【解决方案6】:
      def a():
          i = 1
      
          def b():
              # i = 2
      
              def c():
                  nonlocal i
                  i = 3
      
              c()
              print('b:', i)
      
          b()
          print('a:', i)
      
      
      a()
      

      nonlocal 将在上层范围内搜索,如果没有找到则上层

      > python3 t.py
      b: 3
      a: 1
      

      评论i = 2

      > python3 t.py
      b: 3
      a: 3
      

      【讨论】:

      • 问题是关于 Python 2.6 ;)
      猜你喜欢
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      • 1970-01-01
      • 2020-04-22
      • 2017-05-26
      • 2019-02-05
      • 1970-01-01
      相关资源
      最近更新 更多