Python 隐藏环境以防关闭
我在看这个视频。这个主题与我将要问的问题并没有真正的联系,但视频却引出了这个问题。确切地说,在Python 隐藏环境以防关闭,python,python-3.x,closures,Python,Python 3.x,Closures,我在看这个视频。这个主题与我将要问的问题并没有真正的联系,但视频却引出了这个问题。确切地说,在41:10中,他谈到了python中似乎不存在的一个功能,他谈到了嵌套函数/块的能力,这些函数/块不知道完整的本地上下文,而是知道手动选择的一些变量。基本上,他要求能够从闭包中移除/部分隐藏环境 下面是python中所需功能的外观(例如使用usedecorator): def foo(): x、 y,z=1,2,3 def baz(): 打印(x,y)#打印“12” @使用(y) def bar():
41:10
中,他谈到了python中似乎不存在的一个功能,他谈到了嵌套函数/块的能力,这些函数/块不知道完整的本地上下文,而是知道手动选择的一些变量。基本上,他要求能够从闭包中移除/部分隐藏环境
下面是python中所需功能的外观(例如使用use
decorator):
def foo():
x、 y,z=1,2,3
def baz():
打印(x,y)#打印“12”
@使用(y)
def bar():
打印(y)#应打印“2”
z=4#应该创建一个名为'z'的局部变量`
打印(x)#应引发名称错误(`x`未定义)
bar(),baz())
foo()
我曾尝试实现该装饰器,但没有成功,因此我尝试了一个更简单的目标,即不是部分隐藏环境,而是完全隐藏环境。我发现了一个解决方案:
导入ctypes
def foo():
x、 z=1
def baz():
打印(x)#打印1
@隐藏环境
def巴(y):
打印(y)#打印2
z=3
打印(z)#打印3
打印(x)#引发名称错误
baz(),bar(2)
def hide_环境(f):
def环境不可知论者(*args,**kwargs):
移除环境(f)
返回f(*args,**kwargs)
返回环境不可知
def移除_环境(f):
如果f.uuu闭包为无:
返回
对于f.中的v.\uuuu闭合\uuuu:
py_对象=ctypes.py_对象(v)
ctypes.pythonapi.PyCell_Set(py_obj,None)#看起来可能会出错
foo()
我有四个问题:
use
机制(在python中)hide\u环境的实现是否正确
y
值的单元格地址。我不确定这是如何处理的,但据我所知,当读取foo
时,“编译器”(不确定是否真的应该这样称呼它)将foo
中的所有局部变量放入\uu closure\uu
对象中,这些对象稍后将被bar
和baz
引用。这引出我的最后一个问题:
文档中是否有描述闭包处理方式的地方
这不是Python自带的,但实现它的最简单方法是检查函数使用了什么,如果函数使用太多,则抛出异常:
def allow_closure_vars(*okay_names):
def checker(f):
used_names = set(f.__code__.co_freevars)
bad_names = used_names - set(okay_names)
if bad_names:
raise ValueError(f"Function uses the following variables it shouldn't: {bad_names}")
return f
return checker
def f():
x, y = 1, 2
@allow_closure_vars('x')
def g():
print(y)
g()
f()
尝试定义g
将引发ValueError
您的实现实际上并不禁止闭包变量访问。它只是取消分配变量,就像del
语句那样。该函数仍然可以访问变量,但变量尚未赋值。这可能与外部函数有关,外部函数可能不希望这些变量被取消分配,并且它不会阻止任何代码为变量分配新值。“是否有任何方法来记录这里发生的情况?”似乎是一个非常奇怪的问题。我不太清楚你在问什么;也许您已经给出了一个在母语中很常见但在英语中不常见的短语的直译。文档中是否有描述闭包处理方式的地方?/是否有任何方法可以知道解释器填充\uuuuuu闭包\uuu
单元格时发生了什么?换句话说,我不想看到的是一个指向文档的链接,该文档描述了闭包是什么,或者为什么它们在用户端以这种方式工作。我正在寻找一份具体说明解释器如何处理这一问题的实现文档。“函数仍然可以访问变量,但它们尚未分配”我不确定是否理解其中的区别,据我所知,我可以访问一个空单元格
,该单元格将引发NameError:在赋值之前在封闭范围内引用的自由变量“x”(这基本上是我想要的)。“这可能与外部函数有关,外部函数可能不希望这些变量未赋值”。\uuuu闭包\uuuu
不是本地副本吗?如果我修改了f
的闭包环境,那么这个变化不是只对f
可见吗?“而且它不会阻止任何代码向变量分配新值。”我会更新我的问题,因为我不想阻止bar声明名为x
的局部变量,所以这不是问题。我将尝试与您一起玩解决方案:)@cglace:\uuuuu closure\uuuu
不是本地副本。你基本上是在foo
的范围内执行dely
。啊,好吧,这确实是个问题,我在bar()
中添加了一个try/except
,然后第二次调用baz()
,它确实引发了相同的NameError
。无论如何,我认为你的解决方案符合我所寻找的所有标准