Python: convert string to function name; getattr or equal?

I am editing PROSS.py to work with .cif files for protein structures. Inside the existing PROSS.py there are the following functions (I believe that the correct name, if it is not associated with any class?), Simply exists in 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 a parson for options for command line arguments, and one of the parameters is to specify an alternative method to use, except for unpack_pdb_line. Therefore, the relevant part of the parameter parser:

 ... 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 a function with the same name as the string inside options.unpack_method. How to use getattr etc. to convert a string to the actual function name?

Thanks,

Floor

+4
source share
5 answers

Usually you just use 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] 
+8
source

If you want to use dictionaries (& c) that Python already supports on your behalf, I would suggest:

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

You probably want to check the function signature (and catch exceptions to provide more nice error messages), for example. via inspect , but this is a useful general purpose function. It is easy to add a shortcut dictionary as a reserve if some well-known functions with full line names (including module / package qualifications) are cumbersome to express this way.

Note that we do not use the result of __import__ (it does not work correctly when the function is in the module inside some package, since __import__ returns the name of the top level of the package ... just access to sys.modules after the import is more practical).

+4
source

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

or

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

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

Greetings

+2
source

If you are accepting data from the user, for security reasons, it is probably best to use a manual dict that only accepts a well-defined set of valid user inputs:

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

Ignoring security for a moment, we note in passing that a simple way to go from (variable name string) to (value that the variable name refers to) is to use the global variables () builtin dict:

 unpack_function=globals()['unpack_pdb_line'] 

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

If you need to get into a package for a module or module for a variable, then you can 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 can use it as follows:

 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.

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

Where is 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 support arbitrary names with several dots in them, for example, `` datetime.datetime.now '. Although it does not work for nested modules that require importing, I can’t even remember the stdlib example for such a module.

+1
source

All Articles