导入Package模块

4
这是一组旨在澄清事物,帮助更好理解的问题集,而不是我遇到的问题。
如果我记错了或者这些问题以前已经被回答过,我在这里道歉。
首先,我想要澄清的问题是:
假设:
import scipy

首先,我注意到通常情况下,您不能通过导入包并尝试访问package.module来访问包中的模块。
例如,scipy.io。
通常需要执行import package.module甚至是import astropy.io.fits,或者可以使用from package import module。
我的问题是为什么会这样,为什么它如此随机-取决于包?我似乎无法确定任何稳定的模式。这是因为一些库(包)非常大,为了避免内存问题而只导入核心属性/模块吗?
第二个问题:
它涉及实际检查这些包的大小。是否有任何方法在导入时查看它们的大小?除了尝试之外,还有其他方法可以知道哪些将起作用,哪些不会?我想我可以使用sys.modules进行检查并尝试从那里获得它?
第三个也是最后一个问题:
在我不在树莓派上运行代码并且不必担心内存问题的情况下(如果这是他们不允许直接访问的原因),是否有任何导入包的方法,使其还加载所有子包?
我只是懒惰地想知道是否可能。 我知道这不是好的实践方法,但好奇心害死猫。
只是为了更新并使人们能够查看我所查看的相关问题:
这个答案提供了关于良好一般实践的好建议: Python导入的良好经验法则是什么? 为什么我不能使用scipy.io?就像文档解释的那样,子包为什么不被导入。
然后显然有文档: https://docs.python.org/3/reference/import.html#packages 5.2.1节就是import scipy不会也import scipy.io的原因,但我想知道为什么开发人员不将其自动化处理。
这个问题实际上与我的问题类似,但似乎没有明确的答案。 Python复杂子包导入 问题的状态:
问题1:回答中的好理由
问题2:待定
问题3:待定
3个回答

1
一个包由文件__init__.py表示。因此,包scipyscipy/__init__.py表示。在该文件中,您会看到很多这样的导入:
from scipy.version import version as __version__

这就是为什么scipy.__version__可以工作的原因,尽管__version__实际上存在于scipy.version中。并非所有的软件包都这样做。没有规定何时可以期望出现这种行为。这完全取决于软件包的作者。

好的,基本上这真的取决于个别包。根据 https://docs.python.org/3/reference/import.html#packages 第5.2.1节:“导入parent.one将隐式执行parent/init.py和parent/one/init.py。”由此,我希望在导入astropy.io.fits的情况下,它也会导入astropy。但我不确定这是否正确。(例如:我导入matplotlib.pyplot,但仍然无法使用matplotlib.use()——尽管它不会做任何事情)此外,我仍然困惑为什么人们要这样做而不是自动导入子包。 - nzicher

1
这些导入调用的关键区别在于模块被导入到的命名空间。给定以下示例:
import mypackage
import mypackage.myclass
from mypackage import myclass

第一个示例将__init__.py中公开的所有内容导入到包的命名空间中。即,可以使用mypackage.myclass()访问其元素。第二个示例仅导入mypackage.myclass,并仍将其导入该包的命名空间中,因此仍然可以使用mypackage.myclass()访问它。第三个示例将mypackage.myclass导入当前命名空间,因此可以像在同一脚本中自己定义一样显式地访问myclass()。这可能会隐藏您在其他地方命名的东西。
还有一个重要的用例如下:
import mypackage as mp

这可以让你设置要导入的包所在的命名空间,使其成为缩写或更方便的东西。
就你关于为什么调用import scipy时scipy不会导入所有内容的问题,归根结底是因为该导入调用仅导入__init__.py中开发人员指定的内容。对于特定的scipy,如果你执行:
import scipy
dir(scipy)

你会发现它导入了许多在整个包中使用的类和函数。我怀疑他们故意不导入子模块,以避免在运行时空间中弄乱你不使用的东西。也许有一种自动导入所有内容的方法,但你可能不应该这样做。

好的,你回答的最后一段其实是我的第一个问题的好答案。我想这是一个好观点,他们有意只定义核心函数,不导入子模块以不影响运行时并使它尽可能轻量化。至于你提到的“import mypackage as mp”的观点,我建议不这样做,只有在有冲突时才使用。https://dev59.com/H3VC5IYBdhLWcg3wvUDg?rq=1。这个问题/答案很好地阐述了为什么。 - nzicher
虽然相关问题指出了使用不同名称导入类的好处,例如from package import class as clsimport package.class as cls,但通常情况下,将整个包导入并使用较短的名称进行命名是标准做法。例如,import numpy as npimport matplotlib.pyplot as plt,尤其当你需要频繁引用该命名空间时,这样做十分方便实用。 - Hal Jarrett

1

回答 Q1

当您导入包时,特别是像SciPy这样的大型包,它使用init.py模块初始化模块来防止自动导入所有子包/模块以节省空间。我不会进一步讨论这个问题,因为这已经在此问题中提到在此处记录,并在其他答案中讨论过。

另外,如果您对脚本与模块有疑问,此帖子非常详细。

回答 Q2

要查找软件包的大小,我会指向此帖子,了解如何查找软件包目录, 然后此帖子,了解如何报告特定目录的大小。您可以创建一些组合代码来为您执行两个操作。

回答 Q3

更新:不确定如何实现,因为文档中解释的普通用法 from package import * (类似于问题1)仍然有效:
如果包的__init__.py代码定义了一个名为__all__的列表,则当遇到from package import *时,它被视为应该导入的模块名称列表。

我的第三个问题实际上是关于“import scipy”的,这样它也会导入所有的子包/模块,但我想没有简单的方法可以做到这一点。感谢您澄清了其他所有问题。 - nzicher
我真的以为“from scipy import *”可以解决这个问题...感谢✓ - Nebbles
它并不起作用。它的工作方式与导入mypackage.myclass相同,这不是我想要的。我想要导入mypackage,以便自动导入myclass。 - nzicher
是的,抱歉,我太累了,无法正确理解文档。现在我已经更新了我的帖子以反映这一点。 - Nebbles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接