Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python导入一个子包而不导入其他子包_Python_Packages_Python Import_Python Module - Fatal编程技术网

Python导入一个子包而不导入其他子包

Python导入一个子包而不导入其他子包,python,packages,python-import,python-module,Python,Packages,Python Import,Python Module,我有以下包结构 package __init__.py sub1 __init__.py foo.py # Contains class Foo sub2 __init__.py bar.py # Contains class Bar 我希望能够导入包,并拥有package.Foo和package.Bar,也就是说,我希望子包对用户透明 问题是导入sub2需要很长时间,许多用户根本不关心

我有以下包结构

package
    __init__.py
    sub1
        __init__.py
        foo.py      # Contains class Foo
    sub2
        __init__.py
        bar.py      # Contains class Bar
我希望能够导入包,并拥有
package.Foo
package.Bar
,也就是说,我希望子包对用户透明

问题是导入sub2需要很长时间,许多用户根本不关心sub2中的内容,只想要sub1中的内容。因此,我希望用户能够说
import package.sub1
从package import sub1
只导入sub1并跳过sub2的导入

我知道我可以通过使用
package/\uu init\uuuu.py
contain来实现第一部分

from .sub1 import *
from .sub2 import *
并且具有
package/sub1/\uuuu init\uuuuu.py
be
from.foo import foo
和类似的sub2。但是,即使用户尝试仅导入
package.sub1
,也会始终导入sub1和sub2

相应地,我可以通过将
package/\u init\u.py
设置为空并使用与上面相同的
sub1/\u init\u.py
来实现第二部分。但是,仅仅说
import-package
不会加载sub1或sub2,因此用户必须显式地加载它们,然后参考
package.sub1.Foo


理想情况下,解决方案将在2.7.10和3.5.0中都能工作,但如果两者都不可能,我将接受其中一种解决方案。

您可以将快捷方式添加到模块的
\uu init\uuuuuuuuuuy.py

package/\uuuuu init\uuuuu.py

__all__ = [
    ... add everything you want to be listed for this module
    'Foo',
    'Bar',
    ...
]
from package.sub1.foo import Foo
from package.sub2.bar import Bar
现在您应该可以拨打:

from package import Bar
该类正是针对这种情况提供的:在实际使用模块时延迟加载模块,而不是在导入模块时

要构建惰性加载程序,您可以按照文档中的示例进行操作:

suffixes = importlib.machinery.SOURCE_SUFFIXES
loader = importlib.machinery.SourceFileLoader
lazy_loader = importlib.util.LazyLoader.factory(loader)
finder = importlib.machinery.FileFinder(path, [(lazy_loader, suffixes)])
然后,您可以使用获取模块的规范,并将结果传递给加载它

仅为一个模块手动执行此操作有点麻烦


请注意,搜索“lazy import python”,您会发现许多解决方案有不同的优点和缺点,其中一些在python2.x中运行。然而,上面的
LazyLoader
类是python3.5+

中的官方方法。一个更好的问题是,为什么在
sub2
中有一个长时间运行的模块级代码,因此,事实上,您的问题是:“我希望
导入包。sub1
做的事情比只导入包要少,对吗?如果没有像提前阅读字节码这样的奇怪的黑客,我认为这是不可能的<代码>导入A.B必须先
导入A
。注意(最后一个代码块,第15行)的底部,
import\u模块
是一个递归函数。但是,您可以很容易地拥有第三个子包,
package.everything
,这将真正将
sub1
sub2
导入到同一名称空间。@Veky:这确实是我最后做的事情(好吧,
package.all
,但足够接近了)。这是我的第一个想法,但我决定不这么做,因为它a)会引起与
软件包的错误关联。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,b)对于您不想鼓励人们做的事情来说有点太短了(一个吸引人的麻烦)。这会在
导入软件包之后启用
package.Bar
问题的一部分。我不能让它从子包装中实际装载东西。如果
sub2/\uuuuu init\uuuuuuuupy
来自.bar导入条
,它会返回
ImportError:没有名为'package.bar'的模块
如果它使用绝对导入,我会在延迟加载期间在sys.modules中替换'package.sub2'的
,所以我还是要说
package.sub2.Bar
,而不仅仅是
package.Bar
,如果你(和我一样)不能让lazy loader工作,我的解决方案是只需要一个
包。所有导入所有内容的
(或者所有内容,如果你喜欢的话),顶级包不导入任何内容。有关更多讨论,请参见对该问题的评论