2012-11-01 13 views
27

この質問が既に提起され、回答されている場合にはお詫び申し上げます。 私がしなければならないことは、概念上非常に単純ですが、残念ながら私はオンラインでその答えを見つけることができませんでした。カスタム名によるPythonの動的関数の作成

Python(Python2.7)の動的関数を実行時にカスタム名で作成する必要があります。各関数の本体も実行時に構築する必要がありますが、すべての関数で(ほぼ)同じです。

名前のリストから始めます。

func_names = ["func1", "func2", "func3"] 

名前は単に私が結果になりたい関数func1、func2を、FUNC3、....

されないようにFUNC_NAMEリストは、任意の名前のリストを保持できることに注意してください。

def func1(*args): 
     ... 

    def func2(*args): 
     ... 

    def func3(*args): 
     ... 

私はこれを行う必要がある理由は、各関数名が外部から呼び出されるテストケースに対応するからです。

更新:ユーザー入力はありません。私ははるかに大きなモジュールの2つの端を結んでいます。一方のエンドはテストケースが何かを判断し、テストケースの名前のリストを入力します。もう一方の端は関数自体であり、テストケースの名前と1:1のマッピングを持たなければなりません。だから私はテストケースの名前を持っています、私はそれぞれのテストケースで何をしたいのか分かります。テストケースの名前を持つ関数を作成するだけです。テストケースの名前は実行時に決定されるため、これらのテストケースに基づく関数の作成は実行時に行う必要があります。

更新:このカスタムの名前付き関数をクラスにラップすることもできます。

文字列内の関数の内容を(ほとんど同じであるため)ハードコードすることができます。または、前もって定義した基底クラスの基にすることができます。このコンテンツを関数に取り込む方法を知る必要があります。例えば

:事前に

func_content = """ 
        for arg in args: 
         print arg 
        """ 

おかげで、

マハディ

答えて

1

あなたはevalを使用することもできます。各関数のPython定義を含む文字列(つまり、def func1 ....で始まる複数行の文字列)を作成すると、evalとなります。

しかし、そのような機能ごとに一意の名前が生成されます(例:genfun345)。このような名前には未確認のユーザー入力を使用しないでください。名前がPythonの既知の名前と同じであれば、災害をデバッグするのは難しいでしょう。

これらの機能の入力を信頼していますか?マルウェアや悪用を気にしますか?

ウィキペディアのhygenic macrosを参照してください。

+0

ユーザー入力がありません。私ははるかに大きなモジュールの2つの端を結んでいます。一方のエンドはテストケースが何かを判断し、テストケースの名前のリストを入力します。もう一方の端は関数自体であり、テストケースの名前と1:1のマッピングを持たなければなりません。だから私はテストケースの名前を持っています、私はそれぞれのテストケースで何をしたいのか分かります。テストケースの名前を持つ関数を作成するだけです。テストケースの名前は実行時に決定されるため、これらのテストケースに基づく関数の作成は実行時に行う必要があります。 – mahdiolfat

33

私はあなたがevalやマクロに降下する必要はないと考えています。閉鎖による関数インスタンスの作成はうまくいくはずです。例:

def bindFunction1(name): 
    def func1(*args): 
     for arg in args: 
      print arg 
     return 42 # ... 
    func1.__name__ = name 
    return func1 

def bindFunction2(name): 
    def func2(*args): 
     for arg in args: 
      print arg 
     return 2142 # ... 
    func2.__name__ = name 
    return func2 

ただし、名前でアクセスできるように、これらの関数を名前でいくつかのスコープに追加することをお勧めします。

>>> print bindFunction1('neat') 
<function neat at 0x00000000629099E8> 
>>> print bindFunction2('keen') 
<function keen at 0x0000000072C93DD8> 
+0

シンプルで機能します。 –

6

は、おそらくこの種のものを行うには、イントロスペクションの一種があり、私はそれが問題にニシキヘビのアプローチだろうとは思いません。

私は、第一レベルの市民としてのPythonの機能の性質を利用すべきだと思います。 Shane Hollowayが指摘しているようにクロージャを使用して、好きなように関数の内容をカスタマイズします。動的ネームバインディングの場合、キーが動的に定義された名前である辞書を使用し、値は関数自体になります。

def function_builder(args): 
    def function(more_args): 
     #do stuff based on the values of args 
    return function 

my_dynamic_functions = {} 
my_dynamic_functions[dynamic_name] = function_builder(some_dynamic_args) 

#then use it somewhere else 
my_dynamic_functions[dynamic_name](the_args) 

ご希望の場合はうれしいです。

1

私はあなただけで動的に既存の機能に新しいまたは代替名を割り当てるように聞こえる、正しくお使いの要件を理解していた場合 - 以下の線に沿って何かが仕事をするべきである。その場合には:

import sys 

testcases = [] 
def testcase(f): 
    """ testcase function decorator """ 
    testcases.append(f) 
    return f 

@testcase 
def testcase0(*args): 
    print 'testcase0 called, args:', args 

@testcase 
def testcase1(*args): 
    print 'testcase1 called, args:', args 

@testcase 
def testcase2(*args): 
    print 'testcase2 called, args:', args 

def assign_function_names(func_names, namespace=None): 
    if namespace is None: 
     namespace = sys._getframe(1).f_globals # default to caller's globals 
    for name, func in zip(func_names, testcases): 
     func.__name__ = name # optional 
     namespace[name] = func 

assign_function_names(["funcA", "funcB", "funcC"]) 

funcA(1, 2, 3) 
funcB(4, 5) 
funcC(42) 
+0

お返事ありがとうございます。しかし、そうではありません。それらは既存の関数ではなく、さらに動的に作成される関数の数も不明です(実行時にのみ認識されます)。 – mahdiolfat

+0

"関数の内容をハードコードする"ことができる場合は、.pyファイル内の 'def xxx(yyy):'をそのコンテンツの前に置いて、それを既存の関数にすることもできます。それを文字列に入れ、それを使って動的に関数を作り直すことで得られますか? – martineau

+0

私はあなたが私がここでやろうとしていることを誤解したと思うし、本当に私の質問に答えなかったが、何か他のことをするように言い続けている。それにもかかわらず、ありがとう。私はすでに私の問題を解決しました。 – mahdiolfat

10

同様の問題の解決策を探すときに私はこの問題を見つけたので、Shaneの答えを拡張しました。変数の範囲に注意してください。スコープを定義するジェネレータ関数を使用すると、スコープの問題を回避できます。ここで、クラスのメソッドを定義する例である。使用において

class A(object): 
    pass 

def make_method(name): 
    def _method(self): 
     print("method {0} in {1}".format(name, self)) 
    return _method 

for name in ('one', 'two', 'three'): 
    _method = make_method(name) 
    setattr(A, name, _method) 

In [4]: o = A() 

In [5]: o.one() 
method one in <__main__.A object at 0x1c0ac90> 

In [6]: o1 = A() 

In [7]: o1.one() 
method one in <__main__.A object at 0x1c0ad10> 

In [8]: o.two() 
method two in <__main__.A object at 0x1c0ac90> 

In [9]: o1.two() 
method two in <__main__.A object at 0x1c0ad10> 
関連する問題