Создание динамической функции Python с пользовательскими именами

Извиняюсь, если этот вопрос уже был поднят и дан ответ. То, что мне нужно сделать, очень просто в концепции, но, к сожалению, я не смог найти ответ на этот вопрос в Интернете.

Мне нужно создавать динамические функции в Python (Python2.7) с пользовательскими именами во время выполнения. Тело каждой функции также необходимо создавать во время выполнения, но оно (почти) одинаково для всех функций.

Я начинаю со списка имен.

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

Обратите внимание, что список func_name может содержать список произвольных имен, поэтому имена НЕ будут просто func1, func2, func3, ....

Я хочу, чтобы результат был:

    def func1(*args):
        ...

    def func2(*args):
        ...

    def func3(*args):
        ...

Причина, по которой мне нужно это сделать, заключается в том, что каждое имя функции соответствует тестовому примеру, который затем вызывается из внешнего мира.

Обновить: Пользовательский ввод отсутствует. Я'связывая два конца гораздо большего модуля. Один конец определяет, что представляют собой тестовые случаи, и среди прочего заполняет список тестовых случаев. имена. Другой конец - это сами функции, которые должны иметь отображение 1: 1 с именем тестового примера. Итак, у меня есть название тестовых случаев, я знаю, что я хочу делать с каждым тестовым примером, мне просто нужно создать функции, которые имеют имя тестовых случаев. Поскольку имена тестовых примеров определяются во время выполнения, создание функции на основе этих тестовых примеров также должно выполняться во время выполнения.

ОбновитьЯ также могу обернуть эти пользовательские функции в класс, если это облегчит задачу.

Я могу жестко закодировать содержимое функций (так как они почти одинаковы) в строку, или я могу основать его на ранее определенном базовом классе. Просто нужно знать, как заполнить функции этим контентом.

Например:

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

Заранее спасибо,

мессия

Ответы на вопрос(6)

так как я только что нашел этот вопрос, когда искал решение аналогичной проблемы. Будьте осторожны с областью действия переменных. Вы можете избежать проблем с областью, используя функцию генератора для определения области. Вот пример, который определяет методы класса:

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>
 Xilpex27 апр. 2019 г., 20:40
Спасибо! Вы сэкономили мне часы работы! : D

что вы описываете, я неНе думаю, что вам нужно спускаться в 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="">
</function></function>
 Alan Dong22 дек. 2015 г., 07:21
Просто и работает.

Если вы правильно понимаете ваши требования, кажется, что вы просто хотите динамически присваивать существующим функциям новые или альтернативные имена - в этом случае что-то вроде следующих строк должно выполнить эту работу:

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)
 mahdiolfat03 нояб. 2012 г., 23:59
Мой вопрос был о том, как создавать динамические функции. Это не былот о том, почему нужно было бы сделать один. Если вы знаете, как это сделать, дайте мне знать. Если нет, нетрать свое время.
 martineau02 нояб. 2012 г., 17:25
Если ты можешь "жестко закодировать содержание функций " Вы могли бы также предшествовать этому содержанию сdef xxx(yyy): в .py файл и сделать его существующей функцией - что вы думаетеВы получаете, помещая это в строку и динамически создавая функцию из этого?
 martineau04 нояб. 2012 г., 00:18
@mahdiolfat: Ну, из того, что вы написали, этоне ясно, вам нужно сделать это, не так лиЭто не дает достаточной мотивации, чтобы помочь вам усовершенствовать или улучшить что-то, что кажется ненужным, поэтому объяснение того, почему вы думаете, что вам нужно это сделать, может быть целесообразным.
 mahdiolfat02 нояб. 2012 г., 16:02
Спасибо за ваш ответ. Но это не тот случай. Они не являются существующими функциями, и, кроме того, число функций, которые должны быть динамически созданы, также неизвестно (известно только во время выполнения).
 martineau03 нояб. 2012 г., 16:27
@mahdiolfat: видимо, яя не единственный, кто нет понял. Ты неt ответить на мой вопрос о том, зачем вам нужно динамически создавать функции, если вы заранее знаете их содержание. Динамическое изменение их имени и создание их методов - более понятная потребность, и это относительно легко сделать.
 mahdiolfat03 нояб. 2012 г., 15:23
Я думаю ты'мы неправильно поняли, что яЯ пытаюсь сделать это здесь и на самом деле не отвечаю на мой вопрос, но продолжаю говорить что-то еще Спасибо, тем не менее. Я'мы уже решили мою проблему.

Eval; вы'создам строку, содержащую определение Python каждой функции (то есть многострочную строку, начинающуюся сdef func1 ....) и ты'тогдаeval Это.

Но я бы сгенерировал уникальное имя для каждой такой функции (например,genfun345). Дон»Для таких имен нельзя использовать какой-либо непроверенный пользовательский ввод. Потому что, если имя совпадает с некоторым известным именем в Python, вы попадаете в сложную отладочную катастрофу.

Вы доверяете тем данным, из которых сделаны эти функции? Вы заботитесь о вредоносных программах или злоупотреблениях?

Прочитать огигиенические макросы в википедии.

 mahdiolfat01 нояб. 2012 г., 20:54
Там нет пользовательского ввода. Я'связывая два конца гораздо большего модуля. Один конец определяет, что представляют собой тестовые случаи, и среди прочего заполняет список тестовых случаев. имена. Другой конец - это сами функции, которые должны иметь отображение 1: 1 с именем тестового примера. Итак, у меня есть название тестовых случаев, я знаю, что я хочу делать с каждым тестовым примером, мне просто нужно создать функции, которые имеют имя тестовых случаев. Поскольку имена тестовых примеров определяются во время выполнения, создание функции на основе этих тестовых примеров также должно выполняться во время выполнения.

существует своего рода самоанализ, чтобы делать подобные вещи, но я неНе думаю, что это будет питонный подход к проблеме.

Я думаю, вы должны воспользоваться природой функций в Python как граждане первого уровня. Используйте замыкания, как указывал Шейн Холлоуэй, чтобы настроить содержимое функции так, как вам нравится. Затем для динамической привязки имен используйте словарь, ключами которого являются имена, определенные динамически, а значениями будут сами функции.

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)

Надеюсь, это имеет смысл для вашего варианта использования.

вы можете использоватьmakefunЯ разработал это только для этого. Он поддерживает три способа определения подписи для генерации:

строковое представление, например'foo(a, b=1)'Signature объект, изготовленный вручную или полученный с помощьюinspect.signature на другую функциюсправочная функция. В этом случае выставленная подпись будет идентична этой функции 'подпись

Кроме того, вы можете сказать ему, чтобы добавить созданную функциюСсылка в качестве первого аргумента в вашей реализации, чтобы иметь незначительные изменения поведения в зависимости от того, откуда поступает вызов (какой фасад). Например:

# generic core implementation
def generic_impl(f, *args, **kwargs):
    print("This is generic impl called by %s" % f.__name__)
    # here you could use f.__name__ in a if statement to determine what to do
    if f.__name__ == "func1":
        print("called from func1 !")
    return args, kwargs

my_module = getmodule(generic_impl)

# generate 3 facade functions with various signatures
for f_name, f_params in [("func1", "b, *, a"),
                         ("func2", "*args, **kwargs"),
                         ("func3", "c, *, a, d=None")]:
    # the signature to generate
    f_sig = "%s(%s)" % (f_name, f_params)

    # create the function dynamically
    f = create_function(f_sig, generic_impl, inject_as_first_arg=True)

    # assign the symbol somewhere (local context, module...)
    setattr(my_module, f_name, f)

# grab each function and use it
func1 = getattr(my_module, 'func1')
assert func1(25, a=12) == ((), dict(b=25, a=12))

func2 = getattr(my_module, 'func2')
assert func2(25, a=12) == ((25,), dict(a=12))

func3 = getattr(my_module, 'func3')
assert func3(25, a=12) == ((), dict(c=25, a=12, d=None))

Как вы можете видеть вдокументацияаргументы всегда перенаправляются наkwargs кроме случаев, когда это абсолютно невозможно (var-позиционные подписи, такие как вfunc2).

Ваш ответ на вопрос