在Python Subpackage中导入类导入的请求数超过了

时间:2015-01-29 19:10:00

标签: python python-2.7 python-import python-c-api python-c-extension

概述

我正在运行一些科学模拟,我想用Python处理结果数据。模拟产生的自定义数据类型不是在模拟作者生成的程序链之外使用的,所以不幸的是我需要他们提供给我的东西。

他们要我安装两个文件:

  • 一个名为sdds.py的模块,它定义了一个提供所有用户功能和两个演示的类
  • 一个名为sddsdatamodule.so的已编译模块,仅向sdds.py提供帮助函数。

(我觉得奇怪的是,他们为我提供了两个难以连接的模块,对我来说它看起来不是很好的编码习惯,但使用他们的代码可能比从头重写东西更好。)我不希望将它们直接安装到我的路径中,并排。他们来自同一家公司,他们被设计为共同完成一项特定任务:访问和操作SDDS类型的文件。

所以我想我会把它们放在一个包里。我可以在我的路径上安装它,它将是自包含的,我可以轻松地从一个位置查找和卸载或升级模块。然后,我可以将他们的非Pythonic解决方案隐藏在一个更Pythonic的包中而不会显着改写。看似优雅。

详细

我实际使用的包在这里找到:

http://www.aps.anl.gov/Accelerator_Systems_Division/Accelerator_Operations_Physics/software.shtml#PythonBinaries

不幸的是,他们现在只支持Windows和Mac OS X.编译源代码非常繁琐,显然他们对Linux / Unix没有重要的要求。我有一台Mac,所以谢天谢地,这对我来说不是问题。

所以我的目录树看起来像这样:

SDDSPython/                   My toplevel package
    __init__.py               Designed to only import the SDDS class
    sdds.py                   Defines SDDS class and two demo methods
    sddsdatamodule.so         Defines sddsdata module used by SDDS class.

我的__init__.py文件只包含这个:

from sdds import SDDS

sdds.py文件包含类定义和两个演示定义。 sdds.py文件中唯一的其他代码是:

import sddsdata, sys, time

class SDDS:
    (lots of code here)

def demo(output):
    (lots of code here)

def demo2(output):
    (lots of code here)

然后我可以导入SDDSPython并使用dir检查

>>> import SDDSPython
>>> dir(SDDSPython)
['SDDS', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'sdds', 'sddsdata']

因此,我现在可以通过SDDS

访问SDDSPython.SDDS课程了

问题

SDDSPython.sddsSDDSPython.sddsdata如何加载到SDDSPython名称空间?

>>> SDDSPython.sdds
<module 'SDDSPython.sdds' from 'SDDSPython/sdds.pyc'>
>>> SDDSPython.sddsdata
<module 'SDDSPython.sddsdata' from 'SDDSPython/sddsdatamodule.so'>

我认为通过创建__init__.py文件,我特意将sddssddsdata模块排除在加载到SDDSPython命名空间之外。到底是怎么回事?我只能假设这是由于sddsdatamodule.so文件中的某些内容而发生的?但是模块怎么能影响它的父命名空间呢?我很遗憾,我不知道从哪里开始。我看过C代码,但我没有看到任何可疑的东西。公平地说 - 我可能不知道什么是可疑的东西,我可能对Python的C扩展编程不够熟悉。

2 个答案:

答案 0 :(得分:0)

奇怪的问题 - 我使用类似的测试案例为您做了一些调查。

XML/
    __init__.py       -from indent import XMLIndentGenerator
    indent.py         -contains class XMLIndentGenerator, and Xml
    Sink.py      

似乎从模块导入类,即使您只导入一部分,整个模块也可以按照您描述的方式访问,即:

>>>import XML
>>>XML.indent
<module 'XML.indent' from 'XML\indent.py'>
>>>XML.indent.Xml   #did not include this in the from
<class 'XML.indent.Xml'>
>>>XML.Sink
Traceback (most recent call last):
AttributeError:yadayada no attribute 'Sink'

这是预料之中的,因为import Sink中没有__init__.py .....但是!

我在indent.py中添加了一行:

import Sink

class XMLIndentGenerator(XMLGenerator):
    (code)

现在,由于此类导入了XML包中包含的模块,如果我这样做:

>>>import XML
>>>XML.Sink
<module 'XML.Sink' from 'XML\Sink.pyc'>

因此,似乎因为导入的sdds模块还导入了sddsdata,您就可以访问它了。这回答了问题的“如何”部分,但“为什么”就是这种情况,我确信在文档的某处有答案:)

我希望这会有所帮助 - 当我输入答案时,我确实这样做了!对我来说也是一次学习经历。

答案 1 :(得分:0)

这是因为python导入不会像你想象的那样工作。他们的工作方式如下:

  • 导入机器查找应该是导入所请求模块的文件
  • 创建了一个types.ModuleType实例,其上的几个属性设置为相应的文件(__file____name__等等),并将该对象插入{{1}在它将拥有的完全限定的模块名称下。
  • 如果这是子模块导入(即sdds.py是SDDSPython中的子模块),则新创建的模块作为属性附加到父包的现有python模块。
  • 文件被执行&#34;以该模块为全球范围;该文件定义的所有名称都显示为模块的属性。
  • sys.modules导入的情况下,模块中的属性可能会返回到导入脚本。

这意味着如果我导入的模块(例如,from)仅作为其来源:

foo.py

然后有一个名为import bar 的全局foo,我可以bar访问它。

python中没有容量用于&#34;只执行我想要立即使用的这个python脚本的一部分。&#34;整个过程都在运行。