如何在导入的模块中显示main.py的全局变量?

时间:2018-01-10 15:36:14

标签: python module global-variables

使用此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):
    ...

但我想避免传递数百万次(对于非常短的计算)与参数相同的变量。

1 个答案:

答案 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)