python import_Python Import 详解
import絕對(duì)是我們?cè)谑褂胮ython時(shí)最常用的語(yǔ)句之一了,但其實(shí)關(guān)于import,需要注意的地方還真不少,如導(dǎo)入第三方庫(kù),導(dǎo)入自己寫的庫(kù),導(dǎo)入相對(duì)路徑下文件中的方法,在包內(nèi)部的相對(duì)與絕對(duì)導(dǎo)入等導(dǎo)入源;有導(dǎo)入的順序;有Lazy Load惰性導(dǎo)入方法;有已經(jīng)導(dǎo)入后的重載等等。本文就旨在講清楚這些問題,并提供足夠的示例以供參考。
Import已安裝的第三方庫(kù)
import
import as
from import
from import *
from . import *
import相對(duì)路徑下的文件(非package)
只能引用本目錄下的,子目錄,孫目錄等下的文件,不能引用父目錄中的內(nèi)容。
√ 以下是正確的:
import
from import
from
from .. import
× 以下是錯(cuò)誤的:
import .
from . import
from . import
from .. import
當(dāng)希望import非這些路徑下的文件時(shí):
先把這些文件的父文件夾append到sys.path中,然后直接import它們的名字。
import sys
sys.path.append()
import
在package內(nèi)部import包相對(duì)路徑下的文件
包其實(shí)可以看作是一種特殊的模塊。例如常規(guī)包的目錄中需要包含 __init__.py 文件,當(dāng)包被導(dǎo)入時(shí),該文件的頂層代碼被隱式執(zhí)行,就如同模塊導(dǎo)入時(shí)頂層代碼被執(zhí)行,該文件就像是包的代碼一樣。所以 包是一種特殊的模塊。需要記住的是,所有的包都是模塊,但不是所有的模塊都是包。包中子包和模塊都有 __path__ 屬性,具體地說(shuō),任何包含 __path__ 屬性的模塊被認(rèn)為是包。所有的模塊都有一個(gè)名稱,類似于標(biāo)準(zhǔn)屬性訪問語(yǔ)法,子包與他們父包的名字之間用點(diǎn)隔開。
所有含有包內(nèi)引用的腳本都不能直接被運(yùn)行(python .py),而只能作為包的一部分被導(dǎo)入包外部的其他文件中使用(如from mlib.xxx.xxx import xxx)這里以包名字為mlib為例:
絕對(duì)路徑引用
import mlib.
import mlib.
from mlib. import
相對(duì)路徑引用
import .
import ..
import ..
from . import
from .
from ..
× 錯(cuò)誤引用
import
from import
若想運(yùn)行包內(nèi)某個(gè)含有包引用的(相對(duì)或絕對(duì)都算)腳本:首先,不論如何,你不能試著在包內(nèi)部目錄下運(yùn)行這個(gè)腳本。也就是說(shuō),如果你的包叫mlib,那你需要先在命令行中cd到其外部文件夾,只要不在包內(nèi),其他哪里都行。
python -m , 如:python -m ./mlib/utils/test.py。-m flag允許了用戶運(yùn)行包內(nèi)部的python腳本。
但注意,即使是這樣,依然有一定可能出現(xiàn)相對(duì)導(dǎo)入的問題,這個(gè)要視具體情況而定。
Lazy Load
如果你不一定會(huì)用到某個(gè)模塊,但后續(xù)開發(fā)時(shí)候又很可能會(huì)用到他們,而你既不想每次都手動(dòng)import, 又不想一次性導(dǎo)入一大堆可能使用的package,有沒有解決方案?
還真有!這時(shí)候lazy load將是一個(gè)很好的選擇。
下面是一份TensorFlow中包含的 Lazy Load 的代碼。它可以做到并不真正import一個(gè)包,但在用戶真正調(diào)用該包、該包的子模塊,或是使用Tab自動(dòng)補(bǔ)全時(shí)候把它真正導(dǎo)入。
代碼
import importlib
import types
?
?
class LazyLoader(types.ModuleType):
"""Lazily import a module, mainly to avoid pulling in large dependencies.?`contrib`, and `ffmpeg` are examples of modules that are large and not alwaysneeded, and this allows them to only be loaded when they are used."""
?
def __init__(self, local_name, parent_module_globals, name):
self._local_name = local_name
self._parent_module_globals = parent_module_globals
?
super(LazyLoader, self).__init__(name)
?
def _load(self):
# Import the target module and insert it into the parent's namespace
module = importlib.import_module(self.__name__)
self._parent_module_globals[self._local_name] = module
?
# Update this object's dict so that if someone keeps a reference to the
# LazyLoader, lookups are efficient (__getattr__ is only called on lookups
# that fail).
self.__dict__.update(module.__dict__)
?
return module
?
def __getattr__(self, item):
module = self._load()
return getattr(module, item)
?
def __dir__(self):
module = self._load()
return dir(module)
使用方法:
from import LazyLoader
os = LazyLoader("os", globals(), "os")
op = LazyLoader("op", globals(), "os.path")
np = LazyLoader("np", globals(), "numpy")
或是如果你想更加優(yōu)雅地一次性導(dǎo)入多個(gè)包而不用寫N行重復(fù)代碼:
_import_dict = {
"os": "os",
"sys": "sys",
"time": "time",
"math": "math",
"yaml": "yaml",
"random": "random",
"op": "os.path",
"np": "numpy",
"pd": "pandas",
"pkl": "pickle",
"glob": "glob",
?
"pf": "mlib.file.path_func",
"lang": "mlib.lang"
}
?
for key, value in _import_dict.items():
exec(f"{key}=LazyLoader('{key}', globals(), '{value}')")
你可以自定義你常用的一些模塊和它們的簡(jiǎn)稱,然后每次直接調(diào)用這份代碼即可做到迅速而無(wú)痛import。
Re-import
如果你已經(jīng)load了一個(gè)模塊,但是由對(duì)這個(gè)模塊本身的代碼做出了修改,此時(shí)你也許就需要reload了,尤其是在jupyter環(huán)境下,這將是非常有用的功能。
import
from importlib import reload
reload()
在代碼中通過包的字符串名稱導(dǎo)入包
__import__或importlib.__import__都可以完成該任務(wù),二者完全等價(jià),但根據(jù)python官方文檔建議,個(gè)人在代碼中最好不要使用這個(gè)函數(shù),而是使用其替代品importlib.import_module(name)。
__import__
__import__(name[, globals[, locals[, fromlist[, level]]]])
參數(shù)介紹:name (required): 被加載 module 的名稱
globals (optional): 包含全局變量的字典,該選項(xiàng)很少使用,采用默認(rèn)值 global()
locals (optional): 包含局部變量的字典,內(nèi)部標(biāo)準(zhǔn)實(shí)現(xiàn)未用到該變量,采用默認(rèn)值 - local()
fromlist (Optional): 被導(dǎo)入的 submodule 名稱
level (Optional): 導(dǎo)入路徑選項(xiàng),Python 2 中默認(rèn)為 -1,表示同時(shí)支持 absolute import 和 relative import。Python 3 中默認(rèn)為 0,表示僅支持 absolute import。如果大于 0,則表示相對(duì)導(dǎo)入的父目錄的級(jí)數(shù),即 1 類似于 ‘.’,2 類似于 ‘..’。
使用示例:
# import spam
spam = __import__('spam')
?
# import spam.ham
spam = __import__('spam.ham')
?
# from spam.ham import eggs, sausage as saus
_temp = __import__('spam.ham', fromlist=['eggs', 'sausage'])
eggs = _temp.eggs
saus = _temp.sausage
import_module
importlib.import_module(name, package=None)
它最大的優(yōu)點(diǎn)是方便,易于控制,與常見的import語(yǔ)法幾乎完全一致,且支持絕對(duì)和相對(duì)import。例如:basic=importlib.import_module(".utils.basic", "mlib")。注意當(dāng)name為相對(duì)路徑時(shí),package需要指定其父模塊。Import a module. The name argument specifies what module to import in absolute or relative terms (e.g. either pkg.mod or ..mod). If the name is specified in relative terms, then the package argument must be set to the name of the package which is to act as the anchor for resolving the package name (e.g. import_module('..mod', 'pkg.subpkg') will import pkg.mod).
The pkg.mod), while pkg).
If you are dynamically importing a module that was created since the interpreter began execution (e.g., created a Python source file), you may need to call
Import的順序
加載python時(shí)默認(rèn)導(dǎo)入的標(biāo)準(zhǔn)庫(kù) > 同級(jí)目錄下的文件(程序根目錄) > PYTHONPATH環(huán)境變量設(shè)置的目錄 > 標(biāo)準(zhǔn)庫(kù) > 第三方庫(kù)
關(guān)于第一個(gè)“加載python時(shí)默認(rèn)導(dǎo)入的標(biāo)準(zhǔn)庫(kù) ”,可以參見這篇文章中的解釋。
Reference
總結(jié)
以上是生活随笔為你收集整理的python import_Python Import 详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蟑螂能吸引来吗?
- 下一篇: python设计一个动物类_python