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

发布于 2024-08-11 09:14:23 字数 756 浏览 6 评论 0原文

我正在编辑 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):

我正在为命令行参数添加一个 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 等将字符串转换为实际的函数名称?

谢谢,

保罗

I am editing PROSS.py to work with .cif files for protein structures. Inside the existing PROSS.py, there is the following functions (I believe that's the correct name if it's not associated with any class?), just existing within the .py file:

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

I am adding an optons parser for command line arguments, and one of the options is to specify an alternate method to use besides unpack_pdb_line. So the pertinent part of the options parser is:

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

However, options.unpack_method is a string and I need to use the function with the same name as the string inside options.unpack_method. How do I use getattr etc to convert the string into the actual function name?

Thanks,

Paul

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

牵强ㄟ 2024-08-18 09:14:23

通常,您只需使用字典并存储 (func_name, function) 对:

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

unpack_function = unpack_options[options.unpack_method]

Usually you just use a dict and store (func_name, function) pairs:

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

unpack_function = unpack_options[options.unpack_method]
蘸点软妹酱 2024-08-18 09:14:23

如果你想利用 Python 已经为你保存的字典 (&c),我建议:

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)

你可能需要检查函数的签名(并捕获异常以提供更好的错误消息),例如通过 检查,但这是一个有用的通用功能。
如果某些已知函数的完整字符串名称(包括模块/包限定)难以以这种方式表达,则可以轻松添加快捷方式字典作为后备。

请注意,我们不使用 __import__ 的结果(当函数位于某个包内的模块中时,它无法正常工作,因为 __import__ 返回顶级名称包的...导入后访问 sys.modules 更实用)。

If you want to exploit the dictionaries (&c) that Python's already keeping on your behalf, I'd suggest:

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)

You'll probably want to check the function's signature (and catch exceptions to provide nicer error messages) e.g. via inspect, but this is a useful general-purpose function.
It's easy to add a dictionary of shortcuts, as a fallback, if some known functions full string names (including module/package qualifications) are unwieldy to express this way.

Note we don't use __import__'s result (it doesn't work right when the function is in a module inside some package, as __import__ returns the top-level name of the package... just accessing sys.modules after the import is more practical).

很糊涂小朋友 2024-08-18 09:14:23

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

干杯,

vars()["unpack_pdb_line"]() will work too.

or

globals() or locals() will also work similar way.

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

Cheers,

╰つ倒转 2024-08-18 09:14:23

如果您正在获取用户的输入,为了安全起见,最好是
使用手工制作的字典,它只接受一组明确定义的可接受的用户输入:

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>

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

If you are taking input from a user, for the sake of security it is probably best to
use a hand-made dict which will accept only a well-defined set of admissible user inputs:

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

Ignoring security for a moment, let us note in passing that an easy way to
go from (strings of variable names) to (the value referenced by the variable name)
is to use the globals() builtin dict:

unpack_function=globals()['unpack_pdb_line']

Of course, that will only work if the variable unpack_pdb_line is in the global namespace.

If you need to reach into a packgae for a module, or a module for a variable, then
you could use this function

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

You could use it like this:

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>

It works for nested packages, modules, functions, or (global) variables.

随波逐流 2024-08-18 09:14:23
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 中此类模块的示例。

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

Where 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() is the only one among all answers that supports arbitrary names with multiple dots in them e.g., `'datetime.datetime.now'. Though it doesn't work for nested modules that require import, but I can't even remember an example from stdlib for such module.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文