在Python子包中导入类的导入量超过了请求量

2024-06-26 14:28:59 发布

您现在位置:Python中文网/ 问答频道 /正文

概述

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

他们要我安装两个文件:

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

我觉得这两个模块不可能直接从我的角度来编写代码,而不是直接把它们连接起来。它们来自同一家公司,它们被设计成一起完成一项特定的任务:访问和操作SDDS类型的文件。在

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

细节

我在这里找到了这个包裹:

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

不幸的是,他们现在只支持Windows和macosx。编译源代码是相当繁重的,显然他们对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文件实际上只包含以下内容:

^{pr2}$

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']

所以我现在可以通过SDDSPython.SDDS来访问SDDS

问题

SDDSPython.sdds和{}究竟是如何加载到SDDSPython命名空间的??在

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

我认为通过创建一个__init__.py文件,我明确地排除了sdds和{}模块被加载到SDDSPython命名空间中。怎么回事?我只能假设这是由于sddsdatamodule.so文件中的某些东西造成的?但是一个模块怎么会像这样影响其父级的命名空间呢?我迷路了,不知道从哪里开始。我看过C代码,但没发现任何可疑之处。公平地说,我可能不知道可疑的东西会是什么样子,我可能对为Python编写C扩展不够熟悉。在


Tags: 模块文件代码pyimportso定义init
2条回答

这是因为python导入的工作方式与您想象的不一样。它们是这样工作的:

  • 导入机制查找应该是从导入请求的模块的文件
  • 创建一个types.ModuleType实例,将其上的几个属性设置为相应的文件(__file____name__等等),然后将该对象插入到sys.modules中,并使用它应该具有的完全限定的模块名。在
  • 如果这是子模块导入(即,标准件.py它是SDDSPython中的子模块),新创建的模块作为属性附加到父包的现有python模块。在
  • 该文件以该模块作为其全局作用域“执行”;该文件定义的所有名称都作为该模块的属性显示。在
  • from导入的情况下,模块中的属性可以返回到导入脚本。在

所以这意味着如果我导入一个模块(比如,foo.py),该模块只有:

import bar

然后在foo中有一个全局名为bar,我可以以foo.bar的形式访问它。在

python中没有“只执行我现在要使用的python脚本的一部分”的功能。在

奇怪的问题我用一个类似的测试用例为你做了一些调查。在

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

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

^{pr2}$

这是意料之中的,因为我没有import Sink__init__.py中……但是!在

我添加了一行缩进.py公司名称:

import Sink

class XMLIndentGenerator(XMLGenerator):
    (code)

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

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

因此,由于导入的sdds模块也导入了sddsdata,所以您可以访问它。这回答了你问题中“怎么做”的部分,但是“为什么”是这样的,我相信文档中肯定有答案:)

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

相关问题 更多 >