Как динамически вызывать функции Python
У меня есть этот код:
fields = ['name','email']
def clean_name():
pass
def clean_email():
pass
Как я могу динамически вызвать clean_name()
и clean_email()
?
Например:
for field in fields:
clean_{field}()
Я использовал фигурные скобки, потому что он, как я делал это в PHP, но, очевидно, не работает.
Как это сделать с Python?
Ответы
Ответ 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
. Вероятно, вам придется выполнить его только один раз, так как он останется тем же, если список полей или доступные функции очистки не будут изменены.