从包中导入子模块时,包文件夹中的__init__.py文件将首先执行exec,如何禁用它。有时我只需要一个包中的一个函数,导入整个包有点重。
例如,pandas.util.clipboard
模块不依赖于pandas中的任何其他函数。
from pandas.util.clipboard import clipboard_get
将导入该函数,但也导入所有pandas常用模块。是否有一些方法只导入剪贴板模块,因为它是我自己的应用程序文件夹中的模块。
答案 0 :(得分:6)
没有,按设计。如果要在导入子模块时避免太多开销,只需使用空__init__.py
来定义包。通过这种方式,导入包的开销几乎为零。
如果pandas
不这样做,则没有方式导入pandas.util.clipboard
而无需导入pandas
和{{1}首先您可以做什么,但它是一个巨大的 hack 并且不等效,是将util
模块导入为正常模块而不是作为子模块。您只需找到安装clipboard
的位置(例如pandas
),然后在/usr/lib/pythonX.Y/dist-packages/
(sys.path
中插入父包的路径)。然后,您可以通过执行以下操作导入/usr/lib/pythonX.Y/dist-packages/pandas/util
包:
clipboard
但请注意:
import clipboard
将打印import clipboard
from pandas.util import clipboard as clipboard2
print(clipboard == clipboard2)
。实际上这样做可能会破坏很多代码,因为你从根本上打破了False
机制所假设的一些不变量。
特别是如果子模块使用相对导入引用其他子模块,则导入将失败,并且在其他情况下它将无法正常运行。失败的另一个例子是你必须处理腌制对象。如果您使用导入为import
的模块对某些对象进行了腌制,则不可以使用上面导入的模块pandas.util.clipboard
对其进行去除。
总之,不要!我建议要么:
clipboard
但不需要pandas.util.clipboard
的其余部分,那么您首先不应该使用pandas
,而应使用仅实现pandas
功能的较小包}。如果查看pandas.util.clipboard
source code,您会发现它实际上只是pyperclip
模块版本1.3。您只需在clipboard
中添加此模块,然后使用它而不是site-packages
提供的模块。实际上pandas
团队只在源代码的末尾添加了以下部分:
pandas
扩展一下为什么 python import以这种方式工作。
正如您所知,在python中模块是对象。而且,包是模块也会发生,尽管不是每个模块都是一个包。导入包时如下:
## pandas aliases
clipboard_get = paste
clipboard_set = copy
Python必须:
import pandas.util.clipboard
实例module
pandas
实例module
并将其作为属性添加到util
pandas
实例module
并将其作为属性添加到clipboard
。为了创建util
实例,python 必须在模块中执行代码。
表单的导入:
module
只是语法糖:
from pandas.util import clipboard
请注意,在import pandas.util.clipboard
clipboard = pandas.util.clipboard
del pandas.util
案例中,from
可以是clipboard
/包,也可以是module
内定义的内容。为了检查这一点,解释器必须还导入util
并执行此操作,必须也导入util
。
答案 1 :(得分:4)
我找到了一个使用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()
使用“__”代替“。”仅用于加载文件:
import pandas__util__clipboard as clip
或使用函数加载文件:
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")
答案 2 :(得分:0)
我尝试过这些方法,但无法让它们发挥作用。显然,通过设计它不应该工作..
如果必须这样做,请在您尝试导入的仓库中创建一个新分支,或初始化仓库:
git checkout -b without_init
..然后删除__init__.py
!
从您尝试导入的任何地方,您都可以检查Python是否在正确的分支上,如下所示:
import subprocess
print ("Current branch is:", subprocess.check_output(["git rev-parse --abbrev-ref HEAD"], shell=True).strip().decode())
>> without_init
答案 3 :(得分:0)
使用Python3,如果知道文件的路径,则可以在不执行包含文件的目录中执行__init__
的情况下导入文件。从[importlib示例]:(How to only import sub module without exec __init__.py in the package)
import importlib.util
import sys
# For illustrative purposes.
import tokenize
file_path = tokenize.__file__
module_name = tokenize.__name__
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)