Many Scipy functions have “callable” arguments, i.e. functions that can be called, with the returned data used as input by the calling function. Types of callable arguments include:
- Functions in the active Python module
- Functions in any active loaded library
- Lambda functions
When the callable argument is passed from Excel, using pyxll, the function name will be passed as a text string, which must be converted to a function object in the Python code. Different procedures are required for the three types of function listed above:
- Functions in the active module can be called with the “globals” method (The globals () method returns the dictionary of the current global symbol table. )
- Functions in active loaded libraries can be called with the “getattr” method (The getattr() method returns the value of the attribute of an object.)
- Strings in lambda format can be converted to lambda functions with the eval() function
Examples of each of these methods are included in the code below:
import scipy as sp
import scipy.stats as stats
import numpy as np
mods = {'np': np, 'stats': stats, 'sp': sp}
def GetCallable(func, mod = None):
# Convert string to callable
# Remove spaces and = from start of string
func = func.replace('=', '')
func = func.strip()
# If string starts with 'lambda' convert ^ to **, then convert string to lambda function
if func[0:6] == 'lambda':
func = func.replace('^', '**')
func = eval(func)
# Else if module is not specified, convert string to function from globals
elif mod is None:
func = globals()[func]
# or if mod is specified, convert mod string to module, then func string to function from mod
else:
mod = mods[mod]
func = getattr(mod, func)
return func
The output from this function is a function object that can be passed to any function requiring callable arguments:
@xl_func
@xl_arg('x', 'numpy_array', ndim = 2)
@xl_arg('y', 'numpy_array', ndim = 2)
@xl_arg('rank', 'numpy_array<var>', ndim = 2)
@xl_arg('weigher', 'str')
@xl_arg('mod', 'str')
@xl_arg('additive', 'bool')
def py_weightedtau(x, y, rank = None, weigher = None, mod = None, additive = None):
"""
Compute a weighted version of Kendall's :math:`\tau`.
...
Function argument descriptions
...
"""
if weigher is not None: weigher = GetCallable(weigher, mod)
kwargs = {'rank': rank, 'weigher': weigher, 'additive': additive}
kwargs = {k:v for k,v in kwargs.items() if v is not None}
return stats.weightedtau(x, y, **kwargs)[0]