事情是这样的,我有一个代理保存对远程模块的引用,我将其中一些代理放入 sys.modules
以便我可以像使用本地模块一样使用它。但是其他一些对象被放在远程环境的 __builtin__
模块中(比如一个方便调试或引用的魔术变量)。我不想像 conn.__builtin__.var
这样引用这些变量,我必须替换本地 __builtin__
(这似乎不适用于替换 sys .modules['__builtin__']
或 Hook 全局名称查找规则。
如何?对于一个模块,你可以重载一个 getattr
来做到这一点。但是在像 IPython
这样的交互式解释器中,谁是主要模块或如何做到这一点? 更新: 正如@Nizam Mohamed 所指出的,是的,我可以获得 __main__
模块,但我仍然无法修改它的名称查找角色。
我想将本地环境完全变成远程环境(用于调试控制台)
更新
现在我只迭代所有 __builtin__.__dict__
以及是否有一个不在本地 __builtin__
中的名称。我将名称添加到本地的 __builtin__
。但与名称查找规则相比,它并不是那么动态,如果我在本地 __builtin__
中找不到名称,请尝试远程。
here是类似的讨论。
还有 this问题通过用 sys.modules
中的对象替换模块来模拟模块。但这不适用于 __builtin__
名称查找,我还尝试将 __builtin__.__getattribute__
替换为自定义名称,该自定义名称将首先使用原始查找,然后是失败时自定义一个。但是 __builtin__
的全局名称查找从未调用到 __builtin__.__getattribute__
甚至 __builtin__.__getattribute__('name')
返回所需的值,__builtin__.name
或 name
永远不会返回一个。
最佳答案
使用 IPython shell 的 AST 转换
正如@asmeurer 所说,您可以编写一个简单的 AST 转换器来“ Hook ”变量名查找。基类 ast.NodeTransformer
提供了一个 visit_Name您可以操作的方法。你只需要重载这个方法来重新定义那些存在于远程模块中但不在本地的变量。
以下模块可用作IPython extension :
testAST.py
import ast
modName = "undefined"
modAttr = []
user_ns = {}
class MyTransformer(ast.NodeTransformer):
def visit_Name(self, node):
if node.id in modAttr and not node.id in user_ns:
return self.getName(node)
return node
def getName(self, NameNode):
return ast.Attribute(value=ast.Name(id=modName, ctx=ast.Load()),
attr = NameNode.id,
ctx = NameNode.ctx)
def magic_import(self, line):
global modName, modAttr, user_ns
modName = str(line)
if not self.shell.run_code( compile('import {0}'.format(line), '<string>', 'exec') ):
user_ns = self.shell.user_ns
modAttr = user_ns[line.strip()].__dict__
self.shell.ast_transformers.append(MyTransformer())
print modName, 'imported'
def load_ipython_extension(ip):
ip.define_magic('magic_import', magic_import)
dummyModule.py
robot=" World"
用法:
In [1]: %load_ext testAST
In [2]: %magic_import dummyModule
In [3]: print "Hello" , robot
Hello World
In [4]: dummyModule.robot_II = "Human"
In [5]: print "Hi", robot_II
Hi Human
这种方法的好处是对远程模块的任何修改都会立即生效,因为查找是在语言级别完成的,不会复制和缓存任何对象。
此方法的一个缺点是无法处理动态查找。如果这对您很重要,也许 python_line_transforms
钩子(Hook)更合适。
关于python - 在 python 解释器中 Hook 全局名称查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36835623/