2012-08-11 6 views
7

この機能を使用している場合、内部機能を自分のカスタムバージョンに置き換えるにはどうすればよいですか?ネストされた関数に相当するオーバーライドが存在しますか?

def foo(): 
    def bar(): 
     # I want to change this 
     pass 

    # here starts a long list of functions I want to keep unchanged 
    def baz(): 
     pass 

これを使用すると、メソッドをオーバーライドするのが簡単になります。しかし、ネストされた関数を使ってその方法を理解することはできません。 fooをクラス(または他のもの)に変更することは、私が変更できない与えられたインポートされたモジュールから来ているため、オプションではありません。

+0

'bar'使用される場合には?それは後の関数( 'baz'のようなもの?)で使われていますか?そういう場合にあなたは*置き換えたいでしょうか? –

+0

正確に。それを行うには? – Paolo

+0

functioneのさまざまな内部ディクショナリは、単なるオブジェクトなのでアクセスできます。詳細については、dir関数と言語リファレンスを使用してください。 – Marcin

答えて

10

ここでそれを行うための一つの方法だとして、それを渡すことができます。 (@DSMのように)。残念ながら、foo関数にジャンプして内部構造を混乱させることはほとんどありません。ほとんどの場合は読み取り専用となっているので、手作業で作成したコピーを変更するだけです。

​​

私はすべてのケースをキャッチするつもりはないと確信しています。

  1. 巨大な引数リストがCODETYPE
  2. 渡される:しかし、それはアップし、いくつかのきちんとして行うことができます

    醜いビットである(古いのpython 2.5.1に私のために)例えば働きますco_constsから構成された醜いタプルは、1つのメンバーだけをオーバーライドします。すべての情報がco_constsに置き換えられるかどうかを判断するため、よりスマートな機能がこれを行うことができます。私はprint(foo.func_code.co_consts)を使って手で内部を掘った。

あなたは通訳 コマンドhelp(types.CodeType)を使用してCodeTypeFunctionTypeに関するいくつかの情報を見つけることができます。

更新: これはあまりにも醜いと思ったので、私はそれをよりきれいにするヘルパー機能を構築しました。

# Use our function to get a new version of foo with "bar" replaced by mybar  
foo = monkey_patch_fn(foo, "bar", my_bar) 

# Check it works 
foo() 

ここmonkey_patch_fnの実装があります:あなたが書くことができるヘルパーと

# Returns a copy of original_fn with its internal function 
# called name replaced with new_fn. 
def monkey_patch_fn(original_fn, name, new_fn): 

    #Little helper function to pick out the correct constant 
    def fix_consts(x): 
    if x==None: return None 
    try: 
     if x.co_name == name: 
     return new_fn.func_code 
    except AttributeError, e: 
     pass 
    return x 

    original_code = original_fn.func_code 
    new_consts = tuple(map(fix_consts, original_code.co_consts)) 
    code_type_args = [ 
    "co_argcount", "co_nlocals", "co_stacksize", "co_flags", "co_code", 
    "co_consts", "co_names", "co_varnames", "co_filename", "co_name", 
    "co_firstlineno", "co_lnotab", "co_freevars", "co_cellvars" ] 

    new_code = types.CodeType(
    *[ (getattr(original_code,x) if x!="co_consts" else new_consts) 
     for x in code_type_args ]) 
    return types.FunctionType(new_code, {}) 
+0

この回答に対する両方のコーディングアプローチを持つことで、2倍の洞察が得られます。 – MikeiLL

3

あなたは、関数内部をハッキングによって「正しいことをする」という新しいFOOを作成し、オプションのパラメータ

def foo(bar=None): 
    def _bar(): 
     # I want to change this 
     pass 
    if bar is None: 
     bar = _bar 
+0

私は分かりません。あなたの答えは、与えられた関数を変更することを暗示していませんか?多分私ははっきりしていないかもしれませんが、元の 'foo'を変更することはできません。 Btw、私は少し質問を編集するつもりです。 – Paolo

+4

私はOPがfoo' 'として、モンキーパッチオプションのいくつかの種類を探していると思う「私は変更することはできません特定のインポートされたモジュールから来ています。」 – PaulMcG

関連する問題