如何动态调用 Python 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4246000/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call Python functions dynamically
提问by nemesisdesign
I have this code:
我有这个代码:
fields = ['name','email']
def clean_name():
pass
def clean_email():
pass
How can I call clean_name()and clean_email()dynamically?
我怎样才能动态调用clean_name()和clean_email()?
For example:
例如:
for field in fields:
clean_{field}()
I used the curly brackets because it's how I used to do it in PHP but obviously doesn't work.
我使用大括号是因为它是我过去在 PHP 中使用的方式,但显然不起作用。
How to do this with Python?
如何用 Python 做到这一点?
采纳答案by khachik
If don't want to use globals, varsand don't want make a separate module and/or class to encapsulate functions you want to call dynamically, you can call them as the attributes of the current module:
如果不想使用globals, vars也不想制作单独的模块和/或类来封装要动态调用的函数,可以将它们作为当前模块的属性进行调用:
import sys
...
getattr(sys.modules[__name__], "clean_%s" % fieldname)()
回答by Magnus Hoff
globals()will give you a dictof the global namespace. From this you can get the function you want:
globals()会给你一个dict全局命名空间。从中你可以得到你想要的功能:
f = globals()["clean_%s" % field]
Then call it:
然后调用它:
f()
回答by Matt Joiner
for field in fields:
vars()['clean_' + field]()
回答by Jakob Bowyer
Using globalis a very, very, bad way of doing this. You should be doing it this way:
使用global是一种非常非常糟糕的方式。你应该这样做:
fields = {'name':clean_name,'email':clean_email}
for key in fields:
fields[key]()
Map your functions to values in a dictionary.
将您的函数映射到字典中的值。
Also using vars()[]is wrong too.
使用vars()[]也是错误的。
回答by Alexander Solovyov
It would be better to have a dictionary of such functions than to look in globals().
最好有一个包含此类函数的字典,而不是在globals().
The usual approach is to write a class with such functions:
通常的方法是编写一个具有以下功能的类:
class Cleaner(object):
def clean_name(self):
pass
and then use getattrto get access to them:
然后用于getattr访问它们:
cleaner = Cleaner()
for f in fields:
getattr(cleaner, 'clean_%s' % f)()
You could even move further and do something like this:
你甚至可以更进一步,做这样的事情:
class Cleaner(object):
def __init__(self, fields):
self.fields = fields
def clean(self):
for f in self.fields:
getattr(self, 'clean_%s' % f)()
Then inherit it and declare your clean_<name>methods on an inherited class:
然后继承它并clean_<name>在继承的类上声明您的方法:
cleaner = Cleaner(['one', 'two'])
cleaner.clean()
Actually this can be extended even further to make it more clean. The first step probably will be adding a check with hasattr()if such method exists in your class.
实际上,这可以进一步扩展以使其更干净。第一步可能是添加检查hasattr()您的类中是否存在此类方法。
回答by demas
Here's another way:
这是另一种方式:
myscript.py:
我的脚本.py:
def f1():
print 'f1'
def f2():
print 'f2'
def f3():
print 'f3'
test.py:
测试.py:
import myscript
for i in range(1, 4):
getattr(myscript, 'f%d' % i)()
回答by Spacedman
Here's another way: define the functions then define a dict with the names as keys:
这是另一种方法:定义函数然后定义一个以名称为键的字典:
>>> z=[clean_email, clean_name]
>>> z={"email": clean_email, "name":clean_name}
>>> z['email']()
>>> z['name']()
then you loop over the names as keys.
然后将名称作为键循环。
or how about this one? Construct a string and use 'eval':
或者这个怎么样?构造一个字符串并使用 'eval':
>>> field = "email"
>>> f="clean_"+field+"()"
>>> eval(f)
then just loop and construct the strings for eval.
然后循环并构造eval的字符串。
Note that any method that requires constructing a string for evaluation is regarded as kludgy.
请注意,任何需要构造字符串进行评估的方法都被认为是笨拙的。
回答by martineau
I would use a dictionary which mapped field names to cleaning functions. If some fields don't have corresponding cleaning function, the forloop handling them can be kept simple by providing some sort of default function for those cases. Here's what I mean:
我会使用一个将字段名称映射到清理函数的字典。如果某些字段没有相应的清理功能,则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]()
The code above constructs the function dictionary dynamically by determining if a corresponding function named clean_<field>exists for each one named in the fieldslist. You likely would only have to execute it once since it would remain the same as long as the field list or available cleaning functions aren't changed.
上面的代码通过确定列表中clean_<field>每个命名的函数是否存在相应的命名函数来动态构造函数字典fields。您可能只需要执行一次它,因为只要字段列表或可用的清理功能没有改变,它就会保持不变。
回答by TheHowlingHoaschd
I have come across this problem twice now, and finally came up with a safeand not uglysolution (in my humble opinion).
我也碰到过这个问题,现在的两倍,终于想出了一个安全而不是丑陋的解决方案(愚见)。
RECAPof previous answers:
回顾以前的答案:
globalsis the hacky, fast & easy method, but you have to be super consistent with your function names, and it can break at runtime if variables get overwritten. Also it's un-pythonic, unsafe, unethical, yadda yadda...
globals是一种hacky、快速和简单的方法,但你必须与你的函数名称保持一致,如果变量被覆盖,它可能会在运行时中断。它也是非蟒蛇式的,不安全的,不道德的,yadda yadda ......
Dictionaries(i.e. string-to-function maps) are safer and easy to use... but it annoys me to no end, that i have to spread dictionary assignments across my file, that are easy to lose track of.
字典(即字符串到函数的映射)更安全且易于使用......但它让我无休止地烦恼,我必须在我的文件中传播字典分配,这很容易忘记。
Decoratorsmade the dictionary solution come together for me. Decorators are a pretty way to attach side-effects & transformations to a function definition.
装饰师为我制作了字典解决方案。装饰器是一种将副作用和转换附加到函数定义的漂亮方式。
Example time
示例时间
fields = ['name', 'email', 'address']
# set up our function dictionary
cleaners = {}
# this is a parametered decorator
def add_cleaner(key):
# this is the actual decorator
def _add_cleaner(func):
cleaners[key] = func
return func
return _add_cleaner
Whenever you define a cleaner function, add this to the declaration:
每当您定义更清洁的函数时,请将其添加到声明中:
@add_cleaner('email')
def email_cleaner(email):
#do stuff here
return result
The functions are added to the dictionary as soon as their definition is parsed and can be called like this:
一旦解析了函数的定义,这些函数就会被添加到字典中,并且可以像这样调用:
cleaned_email = cleaners['email'](some_email)
回答by Vlad Bezden
In case if you have a lot of functions and a different number of parameters.
如果您有很多函数和不同数量的参数。
class Cleaner:
@classmethod
def clean(cls, type, *args, **kwargs):
getattr(cls, f"_clean_{type}")(*args, **kwargs)
@classmethod
def _clean_email(cls, *args, **kwargs):
print("invoked _clean_email function")
@classmethod
def _clean_name(cls, *args, **kwargs):
print("invoked _clean_name function")
for type in ["email", "name"]:
Cleaner.clean(type)
Output:
输出:
invoked _clean_email function
invoked _clean_name function

