将变量设置为已导入它的模块的名称

时间:2015-08-03 18:58:57

标签: python django python-3.x django-1.7

假设我有两个模块:

first.package.module

# Assign module to a variable
which_module = ???

print("I originally live in {}".format(__name__))   # Prints first.package.module
print("I was run from {}".format(which_module))

second.package.module

from first.package.module import *

third.package.module

from first.package.module import *

如何在second.package.module中导入第二行“我是从”运行后打印 second.package.module ?或者 third.package.module 从那里运行时。

我想要这种行为的原因是由于在Django中构建了一个在同一个项目中多次使用的应用程序,即同一个应用程序有多个实例。这些实例中的每一个都有自己的模型,这些模型继承自抽象模型。为了构建可重用的视图和URL,我想动态加载模型,为此,我需要知道哪个模块导入了应用程序并运行它。

1 个答案:

答案 0 :(得分:3)

您可以使用以下命令打印触发模块加载的模块名称:

import sys

print sys._getframe(1).f_globals['__name__']

在Python 3中使用新的importlib堆栈,您需要将framecount增加到6(至少3.5,3.6和3.7):

print(sys._getframe(6).f_globals['__name__'])

跨CPython解决方案是过滤掉堆栈中的任何importlib._bootstrap*元素:

import sys

def imported_from(depth=0):
    # skip the frames of this function, and the caller
    f = sys._getframe(2 + depth)
    while f and f.f_code.co_filename.startswith("<frozen importlib._bootstrap"):
        f = f.f_back
    return f and f.f_globals['__name__']

print(imported_from())

上述imported_from()函数可以在实用程序模块中定义并导入; sys._getframe(2)调用确保起始上下文是触发imported_from()调用的任何内容。提供一个正整数作为depth参数,以增加跳过的帧数。该函数适用于提供sys._getframe()函数的任何Python版本,无论它是否使用importlib堆栈。

请注意:

  • 依赖于CPython实现细节(暴露框架堆栈在其他Python实现中不可用)。请参阅sys._getframe() function documentation

      

    CPython实现细节:此函数仅用于内部和专门用途。并不保证在Python的所有实现中都存在。

  • 在Python 3中,它取决于importlib堆栈的确切实现细节;正在进行的开发可以添加或删除该堆栈中的调用。例如,在首次引入importlib的Python 3.3中,要跳过的正确堆栈计数为9,在3.4中它下降到7,并且3.5将其降低到6(自从稳定以来的数字) )。 imported_from()解决了这个问题,但引入了一个新的依赖于实现细节的假设:可以通过查找文件名中的<frozen importlib._bootstrap前缀来检测与导入相关的堆栈帧。从理论上讲,可以编译CPython,importlib._bootstrap保持未冻结(不包括在解释器二进制文件中作为marshal数据的数组)。

  • 仅在第一次导入模块时有效,此时Python执行模块代码以生成sys.modules对象。

我不能强调最后一点。 Python只会加载模块一次。导入过程分为两步:加载和绑定。仅当模块对象尚未存在时才执行加载步骤,模块的所有其他导入仅绑定名称

绑定名称不是你可以实际挂钩的东西;一旦模块已经在内存中,import modulename只不过是modulename = sys.modules['modulename']赋值。