25

リモートモジュールへの参照を保持するプロキシがあり、これらのプロキシのいくつかをsys.modulesローカルモジュールと同じように使用できるようにします。しかし、他のいくつかのオブジェクトは__builtin__、リモート環境でモジュールに入れられます (デバッグや参照に便利なマジック変数など)。のようにこれらの var を参照したくありませんconn.__builtin__.var。ローカル__builtin__を置き換える必要があります (replace では機能しないsys.modules['__builtin__']か、グローバルな名前検索ルールをフックする必要があります。どうすればよいでしょうか?モジュールの場合は、getattrこれを行うために a をオーバーロードするだけです。しかし、のようなインタラクティブなインタープリターIPythonで、メインモジュールは誰ですか、またはこれを行う方法は? 更新: @Nizam Mohamed が指摘したように、はい、取得できます__main__モジュールですが、それでも名前検索の役割を変更できません。

ローカル環境を完全にリモート環境にしたい (デバッグ コンソール用)

アップデート

今のところ__builtin__.__dict__、ローカルにない名前がある場合は、すべてを繰り返すだけ__builtin__です。ローカルの に名前を追加し__builtin__ます。しかし、ローカルで名前が見つからない場合は__builtin__、リモートの名前を試してみてください。

ここに同様の議論があります。

そして、この質問は、モジュールを のオブジェクトに置き換えることで、モジュールのシミュレーションを提供しますsys.modules。しかし、これは名前ルックアップでは機能しません。また、最初に元のルックアップを使用し、失敗したときにカスタム ルックアップを使用するカスタム ルックアップ__builtin__に置き換えようとしました。ただし、イベントに呼び出されないグローバル__builtin__.__getattribute__名のルックアップは、目的の値を返すか、値を返しません。__builtin____builtin__.__getattribute____builtin__.__getattribute__('name')__builtin__.namename

4

2 に答える 2

7

IPython シェルの AST 変換を使用する

@asmeurer が言ったように、単純な AST トランスフォーマーを記述して、変数名のルックアップを「フック」できます。基本クラスは、操作可能なvisit_Nameメソッドをast.NodeTransformer提供します。このメソッドをオーバーロードして、リモート モジュールに存在するがローカルには存在しない変数を再定義する必要があります。

次のモジュールは、 IPython 拡張機能として使用できます。

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)

ダミーモジュール.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

この方法の利点は、ルックアップが言語レベルで行われ、オブジェクトがコピーおよびキャッシュされないため、リモート モジュールへの変更がすぐに有効になることです。

この方法の欠点の 1 つは、動的ルックアップを処理できないことです。それがあなたにとって重要な場合は、python_line_transformsフックの方が適しているかもしれません。

于 2016-05-12T19:08:09.683 に答える
6

モジュールが使用するすべての名前のリストを取得する方法があります。検索メカニズムは変更されませんが、問題は解決すると思います。

これは、モジュールに入れることができるコードです(うまくいけば十分に理解できます)。それを呼び出しましょうmagic

import sys

def magic():
    # Get the caller frame
    frame = sys._getframe().f_back

    # Unwind all internal Python import-related stuff
    while frame.f_code.co_filename.startswith('<'):
        frame = frame.f_back

    importer = frame

    # Iterate through names the module has/will use
    for name in importer.f_code.co_names:

        # If the module has not yet defined/imported this name
        if name not in importer.f_globals and \
                name not in importer.f_locals and \
                name not in __builtins__:

            # Replace the name in the importer's namespace
            # You'll have to replace the right-hand side by your specific code
            importer.f_globals[name] = 'hello world'

次に、それをインポートして魔法をかけることができます。

import magic
magic.magic()

print(hi)

ただし、2 つの欠点があります。まず、動的検索は失敗します。

import magic
magic.magic()

print(globals()['hi']) # KeyError: 'hi'

その特定のケースは の文字列を調べることで解決できますが、次のimporter.f_code.co_constsようなより高度な動的ルックアップでは機能しません。print(globals()['h'+'i'])

2 つ目の欠点は、関数では機能しないことです。

import magic
magic.magic()

def f():
    print(hi) # NameError: name 'hi' is not defined

f()

これは、その場合、名前hif.__code__.co_names モジュールの ではなくin であるためですco_names

考えられる解決策の 1 つmagicは、モジュールのすべての関数を見つけてコードを変更するように変更することですが、関数内で定義された関数などでは機能しません。

magic別の解決策は、関数を呼び出すことです。

import magic

def f():
    magic.magic()
    print(hi)

f()
于 2016-05-06T21:35:25.847 に答える