blu*_*e10 6 python import closures ipython
我有时会embed在脚本中的某个位置使用它来快速充实一些本地功能.最小的例子:
#!/usr/bin/env python
# ...
import IPython
IPython.embed()
Run Code Online (Sandbox Code Playgroud)
开发本地功能通常需要重新导入.但是,在函数中使用时,在IPython会话中导入模块似乎不起作用.例如:
In [1]: import os
In [2]: def local_func(): return os.path.sep
In [3]: local_func()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-f0e5d4635432> in <module>()
----> 1 local_func()
<ipython-input-2-c530ce486a2b> in local_func()
----> 1 def local_func(): return os.path.sep
NameError: global name 'os' is not defined
Run Code Online (Sandbox Code Playgroud)
这是相当令人困惑的,特别是因为我甚至可以使用制表符完成来编写os.path.sep.
我注意到问题更为根本:通常,在IPython嵌入会话中创建的函数不会关闭嵌入范围中的变量.例如,这也失败了:
In [4]: x = 0
In [5]: def local_func(): return x
In [6]: local_func()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-f0e5d4635432> in <module>()
----> 1 local_func()
<ipython-input-5-2116e9532e5c> in local_func()
----> 1 def local_func(): return x
NameError: global name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)
模块名称可能只是"关闭"最常见的事情......
有没有解决这个问题的方法?
更新:问题不仅适用于闭包,还适用于嵌套列表推导.
免责声明:我会自己发布一个(不满意的)问题答案 - 但仍然希望有更好的解决方案.
我也有同样的问题。我使用这个技巧来处理在函数外部调用 的情况embed(),因此globals()和locals()应该是相同的字典。
最简单的方法是在ipython启动后调用以下函数
ipy = get_ipython()
setattr(ipy.__class__, 'user_global_ns', property(lambda self: self.user_ns))
Run Code Online (Sandbox Code Playgroud)
另一种方法是子类化InteractiveShellEmbed
class InteractiveShellEmbedEnhanced(InteractiveShellEmbed):
@property
def user_global_ns(self):
if getattr(self, 'embedded_outside_func', False):
return self.user_ns
else:
return self.user_module.__dict__
def init_frame(self, frame):
if frame.f_code.co_name == '<module>':
self.embedded_outside_func = True
else:
self.embedded_outside_func = False
Run Code Online (Sandbox Code Playgroud)
并稍微修改 的代码,IPython.terminal.embed.embed()以便将其全部InteractiveShellEmbed更改为InteractiveShellEmbedEnhancedand call shell.init_frame(frame)after the line shell = InteractiveShellEmbed.instance(...)。
这是基于以下观察:
id(globals()) == id(ipy.user_module.__dict__) == id(ipy.user_global_ns)(user_global_ns是 的超类的类属性InteractiveShellEmbed,它返回ipy.user_module.__dict__)id(locals()) == id(ipy.user_ns)id(locals()) == id(globals())user_global_ns(属性)和user_ns(字典)定义执行上下文ipy.user_module和ipy.user_ns在函数中设置ipy.__call__()并传递给ipy.mainloop(). 它们不是同一个对象,因为ipy.user_ns是在函数内部构造的。如果您要在函数外部(例如在脚本中)启动 ipython,那么可以安全地假设 应该globals()与locals().
通过此设置,以下代码应该可以工作,但不能使用默认的嵌入式 shell:
a=3
(lambda :a)() # default behavior: name 'a' is not defined
import time
(lambda: time.time())() # default behavior: name 'time' is not defined
Run Code Online (Sandbox Code Playgroud)
(默认行为是由于a并且time不会添加到本地函数(上面定义的 lambda)globals()并且ipython不会对其进行闭包,并且坚持在全局范围内查找变量。closure 在此页面中搜索)
| 归档时间: |
|
| 查看次数: |
576 次 |
| 最近记录: |