使用此main.py
from mymodule import myfunc
GENERALPARAM = "6878623"
for i in xrange(10000):
myfunc(i)
和mymodule.py
:
def myfunc(a):
# very fast computation here
if condition(a):
log(a, GENERALPARAM)
如何在GENERALPARAM
mymodule.py
中提供myfunc
?通过使用全局变量(如何?)?
当然我可以将它作为参数传递:
#main.py
for i in xrange(10000):
myfunc(i, GENERALPARAM)
#mymodule.py
def myfunc(a, GENERALPARAM):
...
但我想避免传递数百万次(对于非常短的计算)与参数相同的变量。
答案 0 :(得分:1)
TL; DR:没有干净的方法,实际上有很好的理由。此外,有机会传递它,因为参数实际上会快,如果不是更快(参数是函数本地的,本地查找比全局查找更快)。
更详细的答案:
"很好的理由"关于可维护性和稳健性。只依赖于它的输入的功能易于理解和测试,并具有可预测的行为。依赖于模块级全局的函数已经难以理解和测试,并且变得难以预测。一个函数取决于主脚本中定义的全局(是的,这可以用hackish方式完成,我不会在这里显示这种方式)不仅完全不可测试且不可预测,而且还要求导入模块确实定义了这个全局,它最多是脆弱的(并且实际上使模块在不同的上下文中不可用)。已经有很多关于"全球化的文章是邪恶的"主题所以我不会进一步解释......
现在wrt / OP的动机,即
我想避免传递数百万次(非常短暂 计算)与参数相同的变量。
我认为OP的主要关注点是表演......
在Python中,将参数传递给函数的成本相当低 - 不会复制任何内容,实际传递的是对象本身的(引用)(有关详细信息,请参阅this reference article from Ned Batcheler on Python's names and values)。此外,参数是函数的局部变量,因此函数执行期间的名称查找是最快的 - 比解析模块全局更快,并且比解析全局模块上的属性快得多。因此,干净而明显的解决方案(将objec作为参数传递)可能会比黑客快得多。
事实上,我对两种解决方案都进行了快速和粗略的基准测试 - 没有timeit模块可以产生更准确的结果,但黑客的本质使得无法在这里使用timeit(是的,黑客攻击)永远不会让你的生活更轻松 - 使用Python 2.7.6和Python 3.4.3,平均差异(在主循环中使用500000次迭代)非常小,实际上小于同一代码版本的两次调用之间的平均差异。我怀疑,对于具有多个变量查找的函数中的实际代码,由于本地查找和全局查找成本,干净的解决方案会变得更快。
我用于基准测试的代码:
清洁解决方案:
# main2.py
import datetime
start = datetime.datetime.now()
from lib2 import myfunc
GENERALPARAM = ["foo", "bar"]
if __name__ == "__main__":
for i in range(500000):
myfunc(i, GENERALPARAM)
done = datetime.datetime.now()
print("done in %s" % (done - start))
# lib2.py
def myfunc(i, p):
return "{} - {}".format(i, p)
黑客解决方案:
# main.py
import datetime
start = datetime.datetime.now()
from lib import myfunc
GENERALPARAM = ["foo", "bar"]
if __name__ == "__main__":
for i in range(500000):
myfunc(i)
done = datetime.datetime.now()
print("done in %s" % (done - start))
# lib.py
import __main__ as main # this is the hack. DONT DO THIS AT HOME
def myfunc(i):
return "{} - {}".format(i, main.GENERALPARAM)