7

インスタンス メソッドのデフォルトのキー引数を動的に設定したいと考えています。たとえば、

class Module(object):
    def __init__(self, **kargs):
        set-default-key-args-of-method(self.run, kargs)  # change run arguments
    def run(self, **kargs):
        print kargs

次のようになります。

m = Module(ans=42)

m.run.im_func.func_code.co_argcount  # => 2
m.run.im_func.func_code.co_varnames  # => ('self','ans','kargs')
m.run.im_func.func_defaults          # => (42,)
m.run()                              # print {'ans':42}

関数 (メソッドではない) に対して types.CodeType (これはよくわかりません) で何かを試してみましたが、動作するようになりました (うまくいかない) が、追加されたキー引数は kargs に表示されませんでした関数の辞書 ({} のみを表示)

変更は、現在のインスタンスに対してのみ行う必要があります。実は今、クラスを使っているので(心の中で○○なのですが)クラスメソッドでやりたいのですが、関数の方がいいかもしれません。何かのようなもの:

def wrapped_run(**kargs):
    def run(**key_args):
        print key_args

    return wrap-the-run-function(run, kargs) 

run = wrapped_run(ans=42)

run.func_code.co_argcount  # => 1
run.func_code.co_varnames  # => ('ans','key_args')  ## keep the 'key_args' or not
run.func_defaults          # => (42,)
run()                      # print {'ans':42}

アドバイスやアイデアは大歓迎です。

コンテキストについて少し:

Module クラスはある種の関数ラッパーであり、ローエンド関数をデータフロー システムに自動的に含めるために使用できますが、中間プロシージャを追加します。データフローシステムが正しいモジュールの入力を透過的に適切に生成するために、モジュール実行関数 (実際には、おそらく __call___ 関数) に正しい API を持たせたいと考えています。

私はpython 2.7を使用しています

4

4 に答える 4

1

閉鎖のために、見つかった唯一の解決策を示します:使用execmgilsonによって提案された)

import os, new

class DynamicKargs(object):
    """
    Class that makes a run method with same arguments
    as those given to the constructor
    """
    def __init__(self, **kargs):
        karg_repr = ','.join([str(key)+'='+repr(value) \
                              for key,value in kargs.iteritems()])
        exec 'def run(self,' + karg_repr + ',**kargs):\n    return self._run(' + karg_repr + ',**kargs)'

        self.run = new.instancemethod(run, self)

    def _run(self, **kargs):
        print kargs

# this can also be done with a function
def _run(**kargs):
    print kargs

def dynamic_kargs(**kargs):
    karg_repr = ','.join([str(key)+'='+repr(value) for key,value in kargs.iteritems()])
    exec 'def run(' + karg_repr + ',**kargs):\n    return _run(' + karg_repr + ',**kargs)'
    return run


# example of use
# --------------
def example():
    dyn_kargs = DynamicKargs(question='ultimate', answer=42)
    print 'Class example \n-------------'
    print 'var number:', dyn_kargs.run.im_func.func_code.co_argcount
    print 'var names: ', dyn_kargs.run.im_func.func_code.co_varnames
    print 'defaults:  ', dyn_kargs.run.im_func.func_defaults
    print 'run print: ', 
    dyn_kargs.run()
    print ''

    dyn_kargs = dynamic_kargs(question='foo', answer='bar')
    print 'Function example \n----------------'
    print 'var number:', dyn_kargs.func_code.co_argcount
    print 'var names: ', dyn_kargs.func_code.co_varnames
    print 'defaults:  ', dyn_kargs.func_defaults
    print 'run print: ', 
    dyn_kargs()

example関数は次を出力します。

Class example 
-------------
var number: 3
var names:  ('self', 'answer', 'question', 'kargs')
defaults:   (42, 'ultimate')
run print:  {'answer': 42, 'question': 'ultimate'}

Function example 
----------------
var number: 2
var names:  ('answer', 'question', 'kargs')
defaults:   ('bar', 'foo')
run print:  {'answer': 'bar', 'question': 'foo'}

でも:

  • 引数の値が適切に表現されていない場合、問題が発生する可能性がありますrepr
  • 複雑すぎると思います(したがってpythonicではありません)。個人的には使用しませんでした
于 2013-05-21T08:55:14.183 に答える
0

これは良い考えとは思えません。関数のシグネチャをいじるよりも、デフォルトのセットをインスタンス変数として定義し、それを関数で使用する方がよいでしょう。

class Module(object):
    def __init__(self, **kwargs):
        self.run_defaults = kwargs
    def run(self, **kwargs):
        actual_values = self.run_defaults.copy()
        actual_values.update(kwargs)
        print actual_values
于 2013-05-02T12:28:15.640 に答える