2009-11-15 40 views
4

我正在编辑PROSS.py以处理蛋白质结构的.cif文件。现有PROSS.py里面,有以下功能(我相信这是正确的名称,如果它不与任何类相关联?),只是.py文件中存在:Python:将字符串转换为函数名称; getattr还是相等?

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

我加入了一个optons解析器用于命令行参数,其中一个选项是指定除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是一个字符串,我需要使用的功能,使用相同的名称作为内部options.unpack_method的字符串。如何使用getattr等将字符串转换为实际的函数名称?

感谢,

保罗

回答

8

通常你只需要使用一个字典和存储(func_name, function)双:

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

unpack_function = unpack_options[options.unpack_method] 
+0

唉唉!辉煌! :-)我想,我需要更多的思考! – TallPaul 2009-11-15 20:27:29

+0

+1使用调度字典更容易和更清晰。 – nosklo 2009-11-16 11:02:30

1

如果从用户采取投入,为安全起见,可能是最好到 使用手工字典,它只接受一组明确定义的可接受用户输入:

unpack_options = { 'unpack_pdb_line' : unpack_pdb_line, 
    'unpack_pdb_line2' : unpack_pdb_line2, 
    } 

暂时忽略安全性,让我们顺便注意一下 从(变量名称的字符串)变为(由变量名称引用的值) 的简单方法是使用globals()内建的字典:

unpack_function=globals()['unpack_pdb_line'] 

当然,只有在变量unpack_pdb_line位于全局命名空间中时,该命令才有效。

如果您需要达到成一个模块,或变量的模块packgae,然后 您可以使用此功能

import sys 
def str_to_obj(astr): 
    print('processing %s'%astr) 
    try: 
     return globals()[astr] 
    except KeyError: 
     try: 
      __import__(astr) 
      mod=sys.modules[astr] 
      return mod 
     except ImportError: 
      module,_,basename=astr.rpartition('.') 
      if module: 
       mod=str_to_obj(module) 
       return getattr(mod,basename) 
      else: 
       raise 

你可以使用这样的:

str_to_obj('scipy.stats') 
# <module 'scipy.stats' from '/usr/lib/python2.6/dist-packages/scipy/stats/__init__.pyc'> 

str_to_obj('scipy.stats.stats') 
# <module 'scipy.stats.stats' from '/usr/lib/python2.6/dist-packages/scipy/stats/stats.pyc'> 

str_to_obj('scipy.stats.stats.chisquare') 
# <function chisquare at 0xa806844> 

它适用于嵌套的包,模块,函数或(全局)变量。

+0

第一个代码段是否有不平衡的右侧paren?谢谢你的回答,所有这些都会有用! – TallPaul 2009-11-15 21:39:33

+0

是的,TallPaul。 (感谢您纠正错字,航海家!) – unutbu 2009-11-16 03:36:30

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进口更实用)。

+0

非常好,谢谢你的答案。我会花一些时间来解决这个问题,但我可以看到这将是多么有用。 – TallPaul 2009-11-15 21:37:43

1
function = eval_dottedname(name if '.' in name else "%s.%s" % (__name__, name)) 

其中eval_dottedname()

def eval_dottedname(dottedname): 
    """ 
    >>> eval_dottedname("os.path.join") #doctest: +ELLIPSIS 
    <function join at 0x...> 
    >>> eval_dottedname("sys.exit") #doctest: +ELLIPSIS 
    <built-in function exit> 
    >>> eval_dottedname("sys") #doctest: +ELLIPSIS 
    <module 'sys' (built-in)> 
    """ 
    return reduce(getattr, dottedname.split(".")[1:], 
        __import__(dottedname.partition(".")[0])) 

eval_dottedname()是所有的答案中只有一个例如支持他们多点的任意名称,` 'datetime.datetime.now'。虽然它不适用于需要导入的嵌套模块,但我甚至不记得stdlib中的这个模块的例子。

2

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 

干杯,

相关问题