python - 在 python 解释器中 Hook 全局名称查找

标签 python ipython python-import rpyc

事情是这样的,我有一个代理保存对远程模块的引用,我将其中一些代理放入 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__.namename 永远不会返回一个。

最佳答案

使用 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/

相关文章:

python - 如何检查我的机器上是否安装了 IPython 以及安装这些库的顺序?

用于测试具有附加依赖项的模块的 Python 导入

python - 无法在正确的 python 版本上安装 python 包?

Python Pandas 从列表中创建多个数据框

python - 什么 HTTP 框架用于简单但可扩展的应用程序?

ipython - 如何关闭 IPython notebook 的文档阅读部分?

python - 导入错误 : No module named <something>

python - 安装成功后CircleCI python模块导入报错

python - 使用转换键的类似字典的类

jquery - 在 Django 中通过 Ajax 输出日志文件