在Python子包中导入类所导入的内容多于请求的内容 概述

在Python子包中导入类所导入的内容多于请求的内容 概述,python,python-2.7,python-import,python-c-api,python-c-extension,Python,Python 2.7,Python Import,Python C Api,Python C Extension,我正在运行一些科学模拟,我想用Python处理生成的数据。模拟生成的自定义数据类型不在模拟作者生成的程序链之外使用,因此不幸的是,我需要他们提供的内容 他们希望我安装两个文件: 一个名为sdds.py的模块,它定义了一个类,该类提供所有用户函数和两个演示 一个名为sddsdatamodule.so的编译模块,它只为sdds.py提供帮助函数。 我觉得奇怪的是,他们给我提供了两个如此紧密相连的模块,对我来说这似乎不是一个好的编码实践,但使用他们的代码可能比从头开始重写要好。我不希望将它们直接并排安

我正在运行一些科学模拟,我想用Python处理生成的数据。模拟生成的自定义数据类型不在模拟作者生成的程序链之外使用,因此不幸的是,我需要他们提供的内容

他们希望我安装两个文件:

一个名为sdds.py的模块,它定义了一个类,该类提供所有用户函数和两个演示 一个名为sddsdatamodule.so的编译模块,它只为sdds.py提供帮助函数。 我觉得奇怪的是,他们给我提供了两个如此紧密相连的模块,对我来说这似乎不是一个好的编码实践,但使用他们的代码可能比从头开始重写要好。我不希望将它们直接并排安装到我的路径中。它们来自同一家公司,它们被设计用来共同完成一项特定任务:访问和操作SDD类型的文件

所以我想我会把它们放在一个包裹里。我可以在我的路径上安装它,它将是独立的,我可以很容易地从一个位置找到并卸载或升级模块。然后我可以将他们的非python解决方案隐藏在一个更python的包中,而无需大量重写。看起来很优雅

细节 我实际使用的软件包可以在这里找到:

不幸的是,他们现在只支持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.
My _init _u;.py文件实际上只包含以下内容:

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

然后,我可以导入SDDSPython并使用dir进行检查:

因此,我现在可以通过SDDSPython.SDDS访问SDDS类

问题 SDDSPython.sdds和SDDSPython.sddsdata究竟是如何加载到SDDSPython名称空间的

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

我认为通过创建一个_uinit__uuu.py文件,我特别排除了SDD和sddsdata模块被加载到SDDSPython名称空间中。发生了什么事?我只能假设这是由于sddsdatamodule.so文件中的某些内容导致的?但是模块如何像那样影响其父级的名称空间呢?我迷路了,不知道从哪里开始。我看过C代码,但没有发现任何可疑之处。公平地说,我可能不知道可疑的东西会是什么样子,我可能对Python的C扩展编程不够熟悉。

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

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'
现在,由于此类导入XML包中包含的模块,如果我这样做:

>>>import XML
>>>XML.Sink
<module 'XML.Sink' from 'XML\Sink.pyc'>
因此,由于导入的sdds模块也导入sdds数据,因此您可以访问它。这就回答了你问题的“如何”部分,但为什么会这样,我相信文档中一定有答案:


我希望这能有所帮助——我在打字的时候确实是这么做的!这对我来说也是一次学习经历。

之所以会发生这种情况,是因为python导入的工作方式与您想象的不一样。它们是这样工作的:

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.
导入机器查找一个文件,该文件应该是从导入请求的模块 创建一个types.ModuleType实例,将其上的几个属性设置为相应的文件_文件_、_名称_等等,然后将该对象插入到sys.modules中,其名称为完全限定的模块名称。 如果这是子模块导入,即sdds.py,它是SDDSPython中的子模块,则新创建的模块将作为属性附加到父包的现有python模块。 该文件以该模块作为其全局作用域执行;该文件定义的所有名称都显示为模块的属性。 对于from导入,模块中的属性可能会返回到导入脚本。 这意味着如果我导入一个模块,比如foo.py,它的源代码只有:

import bar
然后在foo中有一个全局变量,叫做bar,我可以通过foo.bar访问它

python中没有能力只执行我现在要使用的python脚本的一部分。整个过程都在运行。

没错,但在我的例子中,我确实是从SDD在uu init_u.py中导入SDD的。如果我真的导入了SDD,我希望DirsDspython只返回SDD,但DirsDspython.sdds应该包含sddsdata、sys和time。从sdds导入sdds,我想无论如何,sdds应该只从sdds子模块导入类。但不知怎么的,我好像也导入了SDD,SDD数据。sdds导入sdds不应该进行子模块导入,对吗?SDDSPython是您路径上的一个包,sdds就在其中。
当您导入SDD时,无论您是如何完成的,只要python将其作为子模块找到,该子模块就会无条件地作为属性添加到其包含的包中。这是由进口机器完成的,独立于你的uuu init uuuuuuuy.py的其他功能。哦,我明白了。有关于这方面的文档吗?谢谢你在这方面的辛勤工作!我现在明白了,我也很想知道为什么。
>>>import XML
>>>XML.Sink
<module 'XML.Sink' from 'XML\Sink.pyc'>
import bar