Подтвердить что ты не робот

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

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

Мне нужно создать динамические функции в 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
                   """

Спасибо заранее,

Махди

4b9b3361

Ответ 1

Для того, что вы описываете, я не думаю, что вам нужно спуститься в 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>

Ответ 2

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

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>

Ответ 3

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

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

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)

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

Ответ 4

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

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

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

Читайте о гигенных макросах в википедии.

Ответ 5

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

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 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)