nonlocals() 在哪里? [英] Where is nonlocals()?

查看:46
本文介绍了nonlocals() 在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何获取当前作用域的非局部变量?函数 varslocalsglobals 存在,但是有没有函数可以获取 nonlocals?>

为什么在调用 vars 时没有列出非本地变量?

更新

我的问题是无法枚举当前作用域中可用的变量,因为 varsglobals 都不包含非本地变量 AFAICT.

我经常在如下代码中使用 vars:

'{meh[0]}/{meh[3]} {a}{b}{c}'.format(**vars())

如果这些变量中的任何一个在包含函数的范围内,则失败.

解决方案

从正在运行的代码中,您可以轻松获取非局部变量的名称 - 但以调用 locals 给你一本字典有点棘手.

使用的 nonlocal 变量名存储在当前运行的代码对象中,在 co_freevars 属性中.

因此,获取非本地名称是一个问题:

names = inspect.currentframe().f_code.co_freevars

这些变量的内容存储在 __closure__ 属性中(func_closure,在 Python 2 中), 函数对象 代替.(不是代码对象).问题是,如果没有来自外部的帮助",运行代码就没有简单的方法可以访问它正在运行的函数对象.您可以访问链接到代码对象的框架对象,但没有返回到函数对象的链接.(对于顶级定义的函数,可以显式使用函数已知名称,如 def 语句中使用的那样,但是对于返回给调用者的封闭函数,无法知道它的名字也可以).

因此,必须采取一种技巧 - 通过使用 gc 模块(垃圾收集器)获取链接到当前代码对象的所有对象 - 有一个 gc.get_referrers 调用 -它将返回链接到代码对象的所有函数对象.

因此,在具有非局部变量的函数中可以这样做:

导入检查,gc从类型导入 FunctionType定义 a(b):b1 = 2定义 c():非本地 b1打印 (b)代码 = inspect.currentframe().f_code名称 = code.co_freevarsfunction = [func for func in gc.get_referrers(code) if isinstance(func, FunctionType)][0]nonlocals = dict (zip(names, (x.cell_contents for x in function.__closure__ )))打印(非本地人)返回inspect.currentframe()返回 cc = a(5)f = c()

因此检索非本地人的名称和值.但是如果您有多个该函数的实例,这将不起作用(也就是说,如果感兴趣的函数被创建不止一次,并且多次调用生成它的函数)- 因为所有这些实例都将链接到 相同 代码对象.上面的例子假设只有一个函数在运行当前代码——并且在这种情况下可以正常工作.对工厂函数的另一个调用将创建另一个函数,非局部变量可能具有其他值,但具有相同的代码对象 - 上面的 function = 列表生成器将检索所有这些,并任意选择第一个.

正确"函数是当前代码正在执行的函数 - 我试图想出一种检索此信息的方法,但无法获得它.如果可以,我会完成这个答案,但就目前而言,这无法帮助您检索非本地值.

(刚刚发现尝试将eval"与非局部变量名一起使用是行不通的)

看起来,将当前运行的框架链接到保存非局部变量值的函数对象的唯一东西是在运行时在 Python 解释器的本机端内部创建的.除了在运行时使用 ctypes 模块查看解释器数据结构之外,我想不出有什么方法可以解决这个问题,这当然不适合任何实际的生产代码.

底线:您可以可靠地检索非局部变量名称.但看起来您无法以字符串形式获取它们的值(然后重新绑定).

您可以尝试为非本地人"打开功能请求;调用 Python 的错误跟踪器或 Python-ideas 邮件列表.

How do I obtain the non-local variables for the current scope? The functions vars, locals, and globals exist, but is there a function to get the nonlocals?

Why aren't the nonlocals listed when calling vars?

Update

My issue is that there's no way to enumerate the variables available in the current scope, as neither vars or globals includes the non-locals AFAICT.

I frequently use vars in code such as the following:

'{meh[0]}/{meh[3]} {a}{b}{c}'.format(**vars())

Which fails if any of these variables are in the scope of a containing function.

解决方案

From within running code, you can easily get the names of the nonlocal variables - but retriving their content in a way a call to locals gets you a dictionary is a bit trickier.

The used nonlocal variable names are stored in the current running code object, in the co_freevars attribute.

So, getting the nonlocal names is a matter of:

names = inspect.currentframe().f_code.co_freevars

The contents for these variables, however, are stored in the __closure__ attribute (func_closure, in Python 2), of the function object instead. (Not the code object). The problem is that, without "aid from outside", there is no easy way for a running code to get to the function object it is running on. You can get to the frame object, which links to the code object, but there are no links back to the function object. (For a top level defined function one could explicitly use the function known name, as used in the def statement` but for an enclosed function, that is returned to a caller, there is no way of knowing its name either).

So, one has to resort to a trick - getting all the objects that link to the current code object, by using the gc module (garbage collector) - there is a gc.get_referrers call - it will return all the function objects that link to the code object one holds.

So, inside a function with non_local variables one could do:

import inspect, gc

from types import FunctionType

def a(b):
    b1 = 2
    def c():
        nonlocal b1
        print (b)
        code =  inspect.currentframe().f_code  
        names = code.co_freevars
        function = [func for func in gc.get_referrers(code) if isinstance(func, FunctionType)][0]
        nonlocals = dict (zip(names, (x.cell_contents for x in function.__closure__ )))
        print(nonlocals)
        return inspect.currentframe()
    return c

c = a(5)
f = c()

And therefore retrieve the names and values of the nonlocals. But this won't work if you have more than one instance of that function around (that is, if the function of interested was created more than once with more than one call to the functin that generates it) - becasue all of those instances will link to the same code object. The example above, assumes there is only one function running with the current code - and would work correctly in this case. Another call to the factrory function would create another function, with potentially other values for the nonlocal variables, but with the same code object - the function = list genrator above would retrieve all of those, and arbitrarily pick the first of those.

The "correct" function is the one on which the current code is executing - I am trying to think of a way of retrieving this information, but can't get to it. If I can, I will complete this answer, but for now, this can't help you to retrieve the nonlocals values values.

(just found out that trying to use "eval" with a nonlocal variable name won't work as well)

It looks like that the only thing linking the current running frame to the function object where the nonlocal variables values are held is created at run time inside the native side of the Python interpreter. I can't think of a way of getting to it short of using the ctypes module to look at interpreters data structures at runtime, which would, of course, be unsuitable for any actual production code.

The bottom line: you can reliably retrieve the nonlocal variable names. But it looks like you can't get their value given their name as a string (nor rebind then).

You could try opening a feature-request for a "nonlocals" call on Python's bug tracker or on Python-ideas mailing list.

这篇关于nonlocals() 在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆