I am using Python 3.9.12. I have an application where a certain function call will run many times and also has many necessary input arguments. I first coded the function with named inputs (with default values), this was fastest. Then I wanted to "clean up" how the arguments were passed to the function for better organization. For this I tried to use a Python dictionary and a Numpy array. Both of these methods were significantly slower.
Below is a copy of the Python code I am working from:
===============UPDATE========================
It was pointed out by two below that I am calling the helper functions get_par_default() every time unnecessarily so I updated the code and results, same general trend, but times are closer to each other. Seems at the moment that best option is essentially named input arguments and disallow positional argument calls for most of the parameters.
import numpy as np
import time as time
def get_par_default():
return {'a':0.16, 'b':0.18, 'F0':0.0, 's':0.0, 'eps':3.0e-3, 'V':3.0, 'p0':0.30575896, 'p10':0.48998486,'q0':0.06468597,'q10':0.27093151}
def get_par_arr_default():
return np.asarray([0.16,0.18,0.0,0.0,3.0e-3,3.0,0.30575896,0.48998486,0.06468597,0.27093151])
def namedargs(Ep,Eq,a=0.16,b=0.18,F0=0.12,s=0.0,eps=3.0e-3,V=3.0,p0=0.5,p10=0.956,q0=0.1,q10=0.306):
#do some dummy calculation
ans = Ep*Eq*a*b*F0*s*eps*V*p0*p10*q0*q10
return ans
def dictargs(Ep,Eq,pars=get_par_default()):
#do some dummy calculation
ans = Ep*Eq*pars['a']*pars['b']*pars['F0']*pars['s']*pars['eps']*pars['V']*pars['p0']*pars['p10']*pars['q0']*pars['q10']
return ans
def nparrargs(Ep,Eq,pars=get_par_arr_default()):
#do some dummy calculation
ans = Ep*Eq*pars[0]*pars[1]*pars[2]*pars[3]*pars[4]*pars[5]*pars[6]*pars[7]*pars[8]*pars[9]
return ans
#the stuff below is so this functionality can be used as a script
########################################################################
if __name__ == "__main__":
Ep=20.0
Eq=10.0
start = time.time()
for i in range(10000): namedargs(Ep,Eq)
end = time.time()
print('Evaluation Time: {:1.5f} sec.'.format(end-start))
start = time.time()
args=get_par_default()
for i in range(10000): dictargs(Ep,Eq,pars=args)
end = time.time()
print('Evaluation Time: {:1.5f} sec.'.format(end-start))
start = time.time()
args=get_par_arr_default()
for i in range(10000): nparrargs(Ep,Eq,pars=args)
end = time.time()
print('Evaluation Time: {:1.5f} sec.'.format(end-start))
The resulting output when this is run with python argtest.py is:
Evaluation Time: 0.00251 sec.
Evaluation Time: 0.00394 sec.
Evaluation Time: 0.01101 sec.
Why is the version where I pass in arguments as named parameters with default values the fastest by at least 2.6 times faster? Is there a way to retain the excellent organization of the "dictionary" method yet not sacrifice the execution time?