57

この質問がすでに提起され、回答されている場合は、お詫び申し上げます。私がしなければならないことは概念的には非常に単純ですが、残念ながらオンラインで答えを見つけることができませんでした.

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

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

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

func_name リストは任意の名前のリストを保持できるため、単に func1、func2、func3 などの名前にはならないことに注意してください。

結果を次のようにしたい:

    def func1(*args):
        ...

    def func2(*args):
        ...

    def func3(*args):
        ...

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

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

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

関数の内容を (ほとんど同じであるため) 文字列にハードコーディングするか、以前に定義された基本クラスに基づいて作成することができます。このコンテンツを関数に入力する方法を知る必要があります。

例えば:

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

前もって感謝します、

マフディ

4

6 に答える 6

61

あなたが説明したことについては、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>
于 2012-11-01T19:56:33.277 に答える
22

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

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>
于 2013-10-30T20:21:29.583 に答える
8

この種のことを行うための一種の内省があるかもしれませんが、それが問題へのpythonicアプローチではないと思います。

第一レベルの市民として、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)

それがあなたのユースケースに意味があることを願っています。

于 2012-11-01T20:18:14.403 に答える
3

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

ただし、そのような関数ごとに一意の名前を生成します (例: genfun345)。そのような名前に未チェックのユーザー入力を使用しないでください。名前が Python で既知の名前と同じである場合、デバッグが困難な災害に陥ることになるためです。

これらの関数が作成される入力を信頼しますか? マルウェアや悪用に関心がありますか?

ウィキペディアでハイジェニック マクロについて読んでください。

于 2012-11-01T19:42:27.873 に答える
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)
于 2012-11-01T21:59:24.823 に答える