导入时,为什么即使只指定了特定部分,整个模块也会加载?

时间:2013-09-16 19:38:14

标签: python

我试图让我的程序内存占用受到控制。我以为我从导入开始,因为我只使用相当大的PyObjC库中的3-4个函数。但是,我有点惊讶地发现,导入较大模块的特定部分与实际加载到内存中的内容无关。

Memory Profiler输出

在OSX上加载整个Quartz.CoreGraphics库:

Line #    Mem usage    Increment   Line Contents
================================================
    77                             @profile 
    78     7.953 MB     0.000 MB   def test_import_all():
    79    26.734 MB    18.781 MB    import Quartz.CoreGraphics as CG

它以几乎19MB的速度拉入整个库。

尝试只提取我需要的内容会产生相同的19MB结果:

Line #    Mem usage    Increment   Line Contents
================================================
    82                             @profile
    83     7.941 MB     0.000 MB   def test_import_some():
    84    26.727 MB    18.785 MB    from Quartz.CoreGraphics import CGImageGetWidth 

因此,似乎特定的导入与实际加载的内容无关。

只需要一小部分来自其他巨大模块的功能,这似乎是一个常见的用例。有没有办法将从模块加载到内存中,或者这只是使用外部库的结果?

2 个答案:

答案 0 :(得分:5)

这就是模块加载的工作原理。运行时维护一组已加载的模块,因此即使您只导入了几个符号,也可以访问整个模块。这有两个可取的后果:

  • 同一模块的未来导入速度很快。
  • 模块级别的任何具有副作用的代码,只执行一次(禁止重新加载模块),而不是执行可变次数,具体取决于模块在哪些位置导入。

如果您认为模块中的任何函数都可以直接使用其中的名称或通过globals()sys.modules[__name__]eval间接访问模块名称空间,那么这也是不可避免的,管他呢。因此,除非进行一些聪明的优化以证明特定函数不执行此操作(Python实现通常不会烦恼),整个模块命名空间必须在内存中。

答案 1 :(得分:0)

不,没有,因为即使您认为只需要一个函数,该函数也可能需要模块中的其他函数(或类等)。模块是可以通过导入加载的最小代码单元。如果模块可以分成多个独立的部分,并且它足够大,这会对性能产生影响,那么它应该是。否则,您不能仅导入部分和/或如果可以的话无关紧要。