如何只导入包中没有exec __init__.py的子模块

HYR*_*YRY 11 python import module package

从包中导入子模块时,包文件夹中的__init__.py文件将首先执行exec,如何禁用它.有时我只需要一个包中的一个函数,导入整个包有点重.

例如,pandas.util.clipboard模块不依赖于pandas中的任何其他功能.

from pandas.util.clipboard import clipboard_get将导入该函数,还导入所有pandas常用模块.是否有一些方法只导入剪贴板模块,因为它是我自己的应用程序文件夹中的模块.

Bak*_*riu 6

不,没有,按设计.如果要在导入子模块时避免太多开销,只需使用空__init__.pys来定义包.以这种方式,导入包的开销几乎为零.

如果pandas这样做,你无法导入pandas.util.clipboard而无需导入pandasutil第一个.您可以做什么,但它是一个巨大的黑客,它相同,是将clipboard模块导入为普通模块而不是作为子模块.您只需找到pandas安装位置(例如/usr/lib/pythonX.Y/dist-packages/)并在sys.path(/usr/lib/pythonX.Y/dist-packages/pandas/util在您的情况下)插入父包的路径.然后您可以clipboard通过执行以下操作导入包:

import clipboard
Run Code Online (Sandbox Code Playgroud)

但请注意:

import clipboard
from pandas.util import clipboard as clipboard2
print(clipboard == clipboard2)
Run Code Online (Sandbox Code Playgroud)

会打印False.事实上,这样做可能会破坏很多代码,因为你从根本上打破了import机制假设的一些不变量.

特别是,如果子模块参考的其他子模块使用相对导入,导入将失败,并有在那里将无法正常使用的其他情形.失败的另一个例子是你必须处理腌制对象.如果您使用导入的模块对某些对象进行了腌制,pandas.util.clipboard那么您将无法使用clipboard上面导入的模块对其进行去除.

总之,不要!我建议要么:

  • 如果导入包的时间不是真正的问题,请使用它.
  • 或者:尝试搜索替代品.如果你只需要pandas.util.clipboard而不是其他的pandas,你可能不应该pandas首先使用,你应该使用只实现其功能的较小的包clipboard.

如果您查看pandas.util.clipboard源代码,您会发现它实际上只是pyperclip模块版本1.3.您可以在您的模块中添加此模块,site-packages而不是使用它提供的模块pandas.事实上,pandas团队只在源代码的末尾添加了以下部分:

## pandas aliases
clipboard_get = paste
clipboard_set = copy
Run Code Online (Sandbox Code Playgroud)

扩展一下为什么 python导入以这种方式工作.

正如您所知,在python 模块中是对象.而且包也是模块,尽管不是每个模块都是一个包.导入包时,如下所示:

import pandas.util.clipboard
Run Code Online (Sandbox Code Playgroud)

Python必须:

  1. 创建module实例pandas
  2. 创建module实例util并将其作为属性添加到pandas
  3. 创建module实例clipboard并将其作为属性添加到util.

为了创建module实例,python 必须执行模块中的代码.

表格的进口:

from pandas.util import clipboard
Run Code Online (Sandbox Code Playgroud)

只是语法糖:

import pandas.util.clipboard
clipboard = pandas.util.clipboard
del pandas.util
Run Code Online (Sandbox Code Playgroud)

请注意,在这种from情况下clipboard可以是module/ package或只是内部定义的东西util.为了检查这一点,解释器还必须导入util并执行此操作,它还必须导入pandas.

  • 有没有办法让包的 `__init__.py` 知道它是如何导入的?例如,有没有办法让 pandas 的 __init__.py 知道它是从原始语句 from pandas.util import Clipboard 与 import pandas 加载的?这将允许包开发人员允许从不需要包其余部分的任何内容的特定模块导入,例如“constants.py”模块。 (3认同)

HYR*_*YRY 5

sys.meta_path我找到了一种用于挂钩导入过程的方法:

import imp, sys

class DummyLoader(object):

    def load_module(self, name):
        names = name.split("__")
        path = None
        for name in names:
            f, path, info = imp.find_module(name, path)
            path = [path]
        return imp.load_module(name, f, path[0], info)

    def find_module(self, name, path=None):
        if "__" in name and not name.startswith("__"):
            return DummyLoader()
        else:
            return None

if not sys.meta_path:
    sys.meta_path.append(DummyLoader())
else:
    sys.meta_path[0] = DummyLoader()
Run Code Online (Sandbox Code Playgroud)

使用“__”而不是“.” 仅用于加载文件:

import pandas__util__clipboard as clip
Run Code Online (Sandbox Code Playgroud)

或使用函数加载文件:

import imp

def load_module(name):
    names = name.split(".")
    path = None
    for name in names:
        f, path, info = imp.find_module(name, path)
        path = [path]
    return imp.load_module(name, f, path[0], info)    

clip = load_module("pandas.util.clipboard")
Run Code Online (Sandbox Code Playgroud)