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

Как динамически вызывать функции Python

У меня есть этот код:

fields = ['name','email']

def clean_name():
    pass

def clean_email():
    pass

Как я могу динамически вызвать clean_name() и clean_email()?

Например:

for field in fields:
    clean_{field}()

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

Как это сделать с Python?

4b9b3361

Ответ 1

Если вы не хотите использовать globals, vars и не хотите, чтобы отдельный модуль и/или класс инкапсулировали функции, которые вы хотите вызвать динамически, вы можете назвать их атрибутами текущего модуля:

import sys
...
getattr(sys.modules[__name__], "clean_%s" % fieldname)()

Ответ 2

Было бы лучше иметь словарь таких функций, чем смотреть в globals().

Обычный подход заключается в том, чтобы написать класс с такими функциями:

class Cleaner(object):
    def clean_name(self):
        pass

а затем используйте getattr для доступа к ним:

cleaner = Cleaner()
for f in fields:
    getattr(cleaner, 'clean_%s' % f)()

Вы даже можете двигаться дальше и делать что-то вроде этого:

class Cleaner(object):
    def __init__(self, fields):
        self.fields = fields

    def clean(self):
        for f in self.fields:
            getattr(self, 'clean_%s' % f)()

Затем наследуйте его и объявите свои методы clean_<name> в унаследованном классе:

cleaner = Cleaner(['one', 'two'])
cleaner.clean()

На самом деле это может быть расширено еще больше, чтобы сделать его более чистым. Первым шагом, вероятно, будет добавление проверки с помощью hasattr(), если такой метод существует в вашем классе.

Ответ 3

Использование global - очень, очень и плохой способ сделать это. Вы должны делать это следующим образом:

fields = {'name':clean_name,'email':clean_email}

for key in fields:
    fields[key]()

Сопоставьте свои функции со значениями в словаре.

Также неверно использовать vars()[].

Ответ 4

globals() предоставит вам dict глобального пространства имен. Из этого вы можете получить нужную функцию:

f = globals()["clean_%s" % field]

Затем назовите его:

f()

Ответ 5

Здесь другой способ:

myscript.py:

def f1():
    print 'f1'

def f2():
    print 'f2'

def f3():
    print 'f3'

test.py:

import myscript

for i in range(1, 4):
    getattr(myscript, 'f%d' % i)()

Ответ 6

for field in fields:
    vars()['clean_' + field]()

Ответ 7

Здесь другой способ: определить функции, затем определить dict с именами в качестве ключей:

>>> z=[clean_email, clean_name]
>>> z={"email": clean_email, "name":clean_name}
>>> z['email']()
>>> z['name']()

тогда вы перебираете имена в виде ключей.

или как об этом? Постройте строку и используйте "eval":

>>> field = "email"
>>> f="clean_"+field+"()"
>>> eval(f)

затем просто зациклируйте и постройте строки для eval.

Обратите внимание, что любой метод, который требует построения строки для оценки, считается kludgy.

Ответ 8

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

fields = ['name', 'email', 'subject']

def clean_name():
    pass
def clean_email():
    pass

# (one-time) field to cleaning-function map construction
def get_clean_func(field):
    try:
        return eval('clean_'+field)
    except NameError:
        return lambda: None  # do nothing
clean = dict((field, get_clean_func(field)) for field in fields)

# sample usage
for field in fields:
    clean[field]()

Приведенный выше код динамически строит словарь функций, определяя, существует ли соответствующая функция с именем clean_<field> для каждого из них, названного в списке fields. Вероятно, вам придется выполнить его только один раз, так как он останется тем же, если список полей или доступные функции очистки не будут изменены.