2009-07-17 11 views
5

Pythonで関数のローカル名前空間を変更するにはどうすればよいですか? locals()は、関数のローカルネームスペースを関数の内部で呼び出すときに返すことを知っていますが、このようなことをしたいと思います(gがfにアクセスできない場所でこれを行いたい理由がありますが、問題を説明するための些細な、愚かな例):Pythonでローカル名前空間を変更する方法

def g(): 
    pass 

def f(): 
    g() 

f.add_to_locals({'g':g}) 
+0

この奇妙な技術を使用して、あなたの究極の目標は何を動作するようですか?なぜf()の前にg()を定義できないのですか? –

+0

私は実行時に(テスト/嘲笑のために)関数の名前空間を混乱させようとしましたが、失敗しました...ちょうどFYI。 –

+0

「add_to_locals」は何ですか?それは私のために存在しないようです。 'AttributeError: 'function'オブジェクトには属性 'add_to_locals''がありません –

答えて

3

関数が呼び出されていないので、まだ、何の「ローカル」スタックフレームを有していません。最も簡単な解決策は、グローバル・コンテキストを使用することです:

handler = None 
def f(): 
    handler() 

def g(): pass 

handler = g 

それとも、関数オブジェクトにグラムを設定できます

f.g = g 

しかし、私はあなたが内から関数オブジェクトを取得することができますかわかりません関数そのもの。それがメソッドの場合は、selfを使用します。

+0

あなたが*本当に*関数内で関数オブジェクトを使用したい場合は、検査に使用できます。 インポート 輸入PPRINT DEFキー()検査: フレーム= inspect.currentframe() 印刷frame.f_globalsを[フレーム.fucode.co_name] .g fn.g = 'hello' fn() – Ivo

+0

これは、クラス関数、ネストされた関数/クロージャー、ラムダなどで壊れています。デコレータのラップ関数を返します。実際の機能 –

+0

'f'がクラス/インスタンスメソッドの場合はどうなりますか? –

1

実行していない関数にはローカルがありません。関数を実行するとローカルコンテキストが作成され、終了時には破棄されるため、関数の外部から変更する「ローカル名前空間」はありません。

あなたはしかし、このような何かを行うことができます。

def f(): 
    g = [1] 
    def func(): 
     print g[0] 
    return func, g 

f, val = f() 
f() 
val[0] = 2 
f() 

これはリファレンスをシミュレートするために、配列を使用しています。

+2

このサイトでは-1票の説明が本当に必要なので、匿名で理由なく正しい回答を投票することはできません。 –

2

私はあなたが全く別の点からそれに取り組んでいる問題を解決できると思います。
関数はオブジェクトであり、辞書を持っています。そのため、あなたがfにグラムを追加し、それを使用することができます:あなただけのf()に引数を追加し、g()への参照を渡さないのはなぜ

def g(): 
    print "g" 

def f(): 
    f.g() 

f.g = g 
+0

非常に洗練されたソリューション。 +1 – Josip

+0

これはグローバル関数でのみ機能します。 fから確実にfにアクセスする方法はありません。 –

+0

これを拡張できますか? Python関数はオブジェクトであり、ローカルまたはグローバルの場合には違いはありません - あなたが_methods_を意味しない限り、それは全く別の話であり、OPが求めていたものではありません。 –

3

を?

def g(): 
    pass 

def f(func): 
    func() 

f(g) 
2

あなたがこれをしたいと思うのは、関数fがあなたのものではなく他のいくつかのモジュールによって定義されているからです。だから、f()がどのように動作するかを変更したい。特に、gが呼ばれたときに呼び出されるものを変更したいとします。

だから私はこのことをお勧めします:これは、モジュールthirdpartypackageのグローバルグラムを変更します

import thirdpartypackage 

def mynewg(): 
    pass 

thirdpartypackage.g = mynewg 

。したがって、thirdpartypackage.f()が呼び出されると、g()の代わりにmynewg()が呼び出されます。

これで解決できない場合は、実際にg()がf()を使用してインポートされているか、存在していない可能性があります。

import thirdpartypackage 

def mynewg(): 
    pass 

deg mynewf(): 
    mynewg() 

thirdpartypackage.f = mynewf 

つまり、f()は、必要な変更を加えたもので完全に上書きします。

8

あなたにはいくつかのオプションがあります。最初に、あなたの例のgは実際には関数のローカルではないことに注意してください(つまり、その中には割り当てられていません)、グローバルです(つまり、ローカル変数に割り当てられていません)。これは関数が定義されているモジュールで参照されることを意味します。関数が実行されたときに割り当てられる前にではなく、ローカルで外部(バイトコードのパッチが足りない)を変更する方法がないため、これは幸運です。

1つのオプションは、関数のモジュールの名前空間に関数を注入することです。これは機能しますが、変数にアクセスするモジュール内のすべての関数に影響を与えます。

ただ1つの関数に影響を与えるには、そのfunc_globalsを別の場所に指定する必要があります。残念ながら、これは読み取り専用のプロパティですが、あなたは同じボディに機能を再作成することによって、あなたがやりたいことができますが、異なるグローバル名前空間:それはなりますことを除いて

import new 
f = new.function(f.func_code, {'g': my_g_function}, f.func_name, f.func_defaults, f.func_closure) 

fは今、indenticalになります提供された辞書内のグローバルに対してこれは、グローバル名前空間全体を再バインドすることに注意してください。そこにf がある変数がある場合は、を検索します。これはかなり面倒ですが、cpython以外のPythonのバージョンでは動作しないかもしれません。

+1

これが「良い」コードであるかどうかはわかりませんが、まさに私が望むものでした。あるコードベースを別のコードベースに変換していて、他の言語の言語構造をシミュレートできるようにしたかったのです。他の言語はコードをパッケージ化し、そのコードを名前空間に追加または削除することができます。さまざまな機能を無効にするのに便利です。したがって、スタック内の名前空間をファッションのように操作します。これは私がそれを効率的に行うことができる最も近いものです。ありがとう – Demolishun

+0

この 'new'ライブラリは何ですか? –

+0

'exec'や' locals()。update(d) 'に何が問題なのですか? –

0

これは

def add_to_locals(l): 
    l['newlocal'] = 1 

add_to_locals(locals()) 
assert newlocal 
+0

これは関数内では機能しません。名前空間に値を追加しません。 – Demolishun

関連する問題