Python:将字符串转换为函数名;使用getattr还是等号?

6 投票
5 回答
12134 浏览
提问于 2025-04-15 16:02

我正在编辑一个叫做PROSS.py的文件,让它可以处理蛋白质结构的.cif文件。在这个PROSS.py文件里,有一些函数(我觉得这个名字没错,如果它不是属于某个类的话),这些函数就存在于这个.py文件里:

...
def unpack_pdb_line(line, ATOF=_atof, ATOI=_atoi, STRIP=string.strip):
...
...
def read_pdb(f, as_protein=0, as_rna=0, as_dna=0, all_models=0,
    unpack=unpack_pdb_line, atom_build=atom_build):

我正在添加一个选项解析器,用来处理命令行参数,其中一个选项是指定除了unpack_pdb_line之外的其他方法。所以选项解析器中相关的部分是:

...
parser.add_option("--un", dest="unpack_method", default="unpack_pdb_line", type="string", help="Unpack method to use. Default is unpack_pdb_line.")
...
unpack=options.unpack_method

不过,options.unpack_method是一个字符串,我需要用这个字符串里面的名字来调用实际的函数。请问我该怎么用getattr等方法把这个字符串转换成实际的函数名呢?

谢谢,

保罗

5 个回答

3

vars()["unpack_pdb_line"]() 也可以这样使用。

或者

使用 globals()locals() 也能以类似的方式工作。

>>> def a():return 1
>>>
>>> vars()["a"]
<function a at 0x009D1230>
>>>
>>> vars()["a"]()
1
>>> locals()["a"]()
1
>>> globals()["a"]()
1

谢谢!

4

如果你想利用Python已经为你准备好的字典(等等),我建议你可以这样做:

def str2fun(astr):
  module, _, function = astr.rpartition('.')
  if module:
    __import__(module)
    mod = sys.modules[module]
  else:
    mod = sys.modules['__main__']  # or whatever's the "default module"
  return getattr(mod, function)

你可能想检查一下函数的签名(并捕获异常,以提供更友好的错误信息),比如通过使用inspect模块,但这个方法是一个很实用的通用函数。如果某些已知函数的完整名称(包括模块或包的名称)写起来太麻烦,你可以很容易地添加一个快捷方式的字典,作为备用。

需要注意的是,我们不使用__import__的结果(因为当函数在某个包的模块里时,它的工作方式不太对,__import__返回的是包的顶层名称……直接在导入后访问sys.modules会更实用)。

9

通常,你只需要用一个字典来存储 (函数名, 函数) 的配对:

unpack_options = { 'unpack_pdb_line' : unpack_pdb_line,
                   'some_other' : some_other_function }

unpack_function = unpack_options[options.unpack_method]

撰写回答