代码之家  ›  专栏  ›  技术社区  ›  pylang

返回Python中的封闭范围变量

  •  1
  • pylang  · 技术社区  · 7 年前

    鉴于

    我有一个功能, scope ,它可以在封闭的命名空间中声明,即 模块 , 功能 是的。感兴趣的变量位于此函数的正外部。

    如何一般性地访问变量/参数及其在中声明的值 任何 封闭命名空间?

    例子

    捕获函数变量的示例伪代码( b )和参数( c )以下内容:

    a = 1
    def func(c=3)
        b = 2
        def scope():
            return ...
        return scope()
    

    预期产量

    func()
    # {'c': 3, 'b': 2}
    

    尝试

    我在模块级取得了一定的成功。 a = 1 以下内容:

    # module-level
    a = 1
    def scope():
        return {k: v for k, v in globals().items() if not k.startswith("_")}
    
    scope()
    # {'a': 1, ...}
    

    我还可以从方法访问类属性,例如。 b = 2 以下内容:

    # class-level
    a = 1
    class Klass:
        b = 2
        def scope(self):
            obj = self.__class__
            return obj.__dict__
    
    Klass().scope()
    # {'b': 2, ...}
    

    我只能部分访问封闭函数中的变量和参数:

    # function-level
    a = 1
    def func(c=3):
        b = 2
        def scope():
            obj = func
            return obj.__code__.co_varnames
        return scope()
    
    func()
    # ('c', 'b', 'scope')
    

    __code__.co_varnames 成功地给出封闭变量(不包括 a ,我也对这些值感兴趣(例如 {'c': 3, 'b': 2} )

    我做了很多未提及的尝试,包括 inspect 函数、其他代码对象方法, dir() ,和对象特殊方法。我的首选是实现更通用和更惯用的代码来检测封闭命名空间中的变量,尽管任何建议都值得赞赏。

    我也知道python的习语和这个问题的本质。我仍然对它的可能性很感兴趣,我感谢任何愿意超越常规的人。

    2 回复  |  直到 7 年前
        1
  •  1
  •   das-g DuXeN0N    7 年前

    有点作弊,但是

    def scope(outer=locals()):
        return outer
    

    作品。(这是欺骗,因为定义代码在定义时计算默认参数,因此 locals() 在封闭范围内运行,因此它实际上不是 scope 函数扩展到封闭范围。)

    注意,返回的目录 局部变量() 在调用后修改相应的作用域时,可以更改,也可以不更改。如果希望在python实现之间(甚至在不同的用例之间)保持一致的行为,请在默认参数或 范围 功能。

    # module-level
    
    a = 1
    
    def scope(outer=locals()):
        return outer
    
    e = 5
    result = scope()
    f = 6
    
    public_result = {k: v for k, v in result.items() if not k.startswith('_')}
    assert (
        # allowed:
        public_result == dict(a=1)
        or
        # C-Python 3.6 behavior:
        public_result == dict(a=1, scope=scope, e=5, result=result, f=6)
    )
    
    # class-level
    
    a = 1
    
    
    class Klass:
        b = 2
    
        @staticmethod
        def _scope(outer=locals()):  # Hidden from public result, because I have
            return outer             # no idea how to refer to it from the outside.
    
        d = 4
    
    
    e = 5
    result = Klass._scope()
    f = 6
    
    public_result = {k: v for k, v in result.items() if not k.startswith('_')}
    assert (
        # allowed:
        public_result == dict(b=2)
        or
        # CPython 3.6 behavior:
        public_result == dict(b=2, d=4)  # would also contain `scope` if it wasn't hidden
    )
    
    # function-level
    
    a = 1
    
    
    def func(c=3):
        b = 2
    
        def scope(outer=locals()):
            return outer
    
        return scope(), scope
    
        d = 4
    
    
    e = 5
    result, scope_fu = func()
    f = 6
    
    assert (
        # C-Python 3.6 behaviour:
        result == dict(b=2, c=3)
        or
        # also allowed:
        result == dict(b=2, c=3, scope=scope_fu, d=4)
    )
    
        2
  •  1
  •   BowlingHawk95    7 年前

    虽然python会给你这样做的方法,但你真的不想这样做。函数/类/etc不应将其内部公开给调用代码,因为这会破坏抽象并使代码变得脆弱。函数应该接受参数并返回输出值,但是不应该公开内部算法,尤其是变量名。