python学习之路之:import(详细介绍import的各种调用原理和使用方法)
import 使用
- 【介紹】
- 【用法】
- import語句的第一種用法::
- **import module_name。**
- import語句的第二種用法:
- if __name__ == '__main__':
- 【其他用法】
- as 改module_name名
- 只使用模塊中的某些內(nèi)容
- 導(dǎo)入元素過多
【介紹】
import語句用來導(dǎo)入其他python文件(稱為模塊module),使用該模塊里定義的類、方法或者變量,從而達(dá)到代碼復(fù)用的目的。
【用法】
首先,先建立一個(gè)文件夾testfile作為工作目錄,并在其內(nèi)建立兩個(gè)文件test1.py和test2.py,
在test1.py寫入代碼:
在test2.py寫入代碼:
def printtittle():print('I'm test2')打開命令行,進(jìn)入到testfile目錄下,敲下python test1.py運(yùn)行,發(fā)現(xiàn)沒有報(bào)錯(cuò),且打印出I’m test2,說明這樣使用import沒有問題。
由此我們總結(jié)出import語句的第一種用法。
import語句的第一種用法::
import module_name。
即import后直接接模塊名。在這種情況下,Python會在兩個(gè)地方尋找這個(gè)模塊,
第一是:sys.path
(通過運(yùn)行代碼import sys; print(sys.path)查看),os這個(gè)模塊所在的目錄就在列表sys.path中,一般安裝的Python庫的目錄都可以在sys.path中找到(前提是要將Python的安裝目錄添加到電腦的環(huán)境變量),所以對于安裝好的庫,我們直接import即可。當(dāng)你import的時(shí)候,python解釋器只會在sys.path這個(gè)變量(一個(gè)list,你可以print出來看)里面的路徑中找可能匹配的package或module。
而一個(gè)package跟一個(gè)普通文件夾的區(qū)別在于:
package的文件夾中多了一個(gè)__init__.py文件。換句話說,如果你在某個(gè)文件夾中添加了一個(gè)__init__.py文件,則python就認(rèn)為這個(gè)文件夾是一個(gè)python中的package。
init.py文件的內(nèi)容可以是空的(package里面必備這個(gè)模塊,.py的文件就是模塊,這個(gè)知識點(diǎn)要知道),它只是告訴python當(dāng)前文件夾是一個(gè)python中的package。當(dāng)然,你可以在這個(gè)__init__.py的module里面添加一些代碼,這些代碼會在import這個(gè)package的時(shí)候運(yùn)行,也就是package下__init__.py模塊,會在import package后,立刻會從無縮進(jìn)的地方開始執(zhí)行代碼。
所以,請確保你要import的py文件所在的目錄有__init__.py文件。(參考)
第二是:運(yùn)行文件
(這里是test1.py)所在的目錄,因?yàn)閠est2.py和運(yùn)行文件test1.py在同一目錄下,所以上述寫法沒有問題。
用上述方法導(dǎo)入原有的sys.path中的庫沒有問題。但是,最好不要用上述方法導(dǎo)入同目錄下的文件!因?yàn)檫@可能會出錯(cuò)。演示這個(gè)錯(cuò)誤需要用到import語句的第二種寫法,所以先來學(xué)一學(xué)import的第二種寫法。
用法二:testtest
在testfile目錄下新建一個(gè)目錄Branch,在Branch中新建文件test3.py,test3.py的內(nèi)容如下:
如何在test1中導(dǎo)入test3.py呢,請看更改后的test1.py:
from Branch import test3 test3.printSelf()import語句的第二種用法:
- from package_name import module_name。
一般把模塊組成的集合稱為包(package)。與第一種寫法類似,Python會在sys.path和運(yùn)行文件目錄這兩個(gè)地方尋找包,然后導(dǎo)入包中名為module_name的模塊。
現(xiàn)在我們來說明為什么不要用import的第一種寫法來導(dǎo)入同目錄下的文件。在Branch目錄下新建test4.py文件,test4.py的內(nèi)容如下:
def printSelf():print('I'm test4')然后我們在test3.py中直接導(dǎo)入test4,test3.py變?yōu)?#xff1a;
import test4 def printSelf():print('I'm test3')這時(shí)候運(yùn)行test1.py就會報(bào)錯(cuò)了,說沒法導(dǎo)入test4模塊。why?
我們來看一下導(dǎo)入流程:test1使用from Branch import test3導(dǎo)入test3,然后在test3.py中用import test4導(dǎo)入test4。
看出問題了嗎?
test4.py和test1.py不在同一目錄,所以在test1運(yùn)行時(shí),因?yàn)椴荒苤苯邮褂胕mport m4導(dǎo)入m4所以報(bào)錯(cuò)。如果我們直接在testfile目錄下新建另一個(gè)test4.py文件,你會發(fā)現(xiàn)再運(yùn)行test1.py就不會出錯(cuò)了,只不過導(dǎo)入的是與test1同一目錄下的test4.py而不是與test3同目錄的test4
面對上面的錯(cuò)誤,使用python2運(yùn)行test1.py就不會報(bào)錯(cuò),因?yàn)樵趐ython2中,上面提到的import的兩種寫法都屬于相對導(dǎo)入,而在python3中,卻屬于絕對導(dǎo)入。
話說到了這里,就要牽扯到import中最關(guān)鍵的部分了——相對導(dǎo)入和絕對導(dǎo)入
上面提到的兩種寫法屬于絕對導(dǎo)入,即用于導(dǎo)入sys.path中的包和運(yùn)行文件所在目錄下的包。對于sys.path中的包,這種寫法毫無問題;導(dǎo)入自己寫的文件,如果是非運(yùn)行入口文件(可以理解為test2/3/4.py文件)(上面的test1.py是運(yùn)行入口文件,可以使用絕對導(dǎo)入),則需要相對導(dǎo)入。
testtest
比如對于非運(yùn)行入口文件test3.py,其導(dǎo)入test4.py需要使用相對導(dǎo)入:
修改如下
from . import test4 def printtestSelf():print('I'm test3')這時(shí)候再運(yùn)行test1.py就ok了。列舉一下相對導(dǎo)入的寫法:
- from . import module_name
導(dǎo)入和自己同目錄下的模塊。 - from .package_name import module_name
導(dǎo)入和自己同目錄的包的模塊。(同級導(dǎo)入) - from … import module_name
導(dǎo)入上級目錄的模塊。(上級導(dǎo)入) - from …package_name import module_name
導(dǎo)入位于上級目錄下的包的模塊。
當(dāng)然還可以有更多的,每多一個(gè)點(diǎn)就多往上一層目錄。
每多一個(gè)點(diǎn)就多往上一層目錄。
每多一個(gè)點(diǎn)就多往上一層目錄。
上面的test1.py是運(yùn)行入口文件,可以使用絕對導(dǎo)入,這句話是沒問題的,和平時(shí)的做法一致。那么,運(yùn)行入口文件可不可以使用相對導(dǎo)入呢?比如test1.py內(nèi)容改成:
from .Branch import test3 test3.printSelf()答案是可以,但不能用python test1.py命令,而是需要進(jìn)入到testfile所在的目錄,使用python -m testfile.test1來運(yùn)行。
為什么?關(guān)于前者,PEP 328提案中的一段文字好像給出了原因:
Relative imports use a module's _name_ attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to '__main__') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.為了加深學(xué)習(xí),我們引入另外一個(gè)知識點(diǎn)
if name == ‘main’:
下面一段代碼:
if __name__ == '__main__':main()意思是:
- 如果運(yùn)行了當(dāng)前文件,則__name__變量會置為__main__,然后會執(zhí)行main函數(shù),
- 如果當(dāng)前文件是被其他文件作為模塊導(dǎo)入的話,則__name__為模塊名,不等于__main__,就不會執(zhí)行main函數(shù)。
- 比如對于上述更改后的test1.py,執(zhí)行python test1.py命令后,會報(bào)如下錯(cuò)誤:
Traceback (most recent call last): File “test1.py”, line 1, in from .Branch import test3 ModuleNotFoundError: No module named ‘main.Branch’; ‘main’ is not a package
據(jù)此我猜測執(zhí)行python test1.py命令后,當(dāng)前目錄所代表的包’.'變成了__main__。
那為什么python -m testfile.test1就可以呢?那位臺灣老師給出了解釋:
執(zhí)行指令中的-test是為了讓Python預(yù)先import你要的package或module給你,然后再執(zhí)行script。
即不把test1.py當(dāng)作運(yùn)行入口文件,而是也把它當(dāng)作被導(dǎo)入的模塊,這就和非運(yùn)行入口文件有一樣的表現(xiàn)了。
注意,在testfile目錄下運(yùn)行python -m test1是不可以的,會報(bào) ImportError: attempted relative import with no known parent package的錯(cuò)誤。因?yàn)閠est1.py中的from .Branch import test3中的. ,解釋器并不知道是哪一個(gè)package。使用python -m testfile.test1,解釋器就知道.對應(yīng)的是testfile這個(gè)package。
那反過來,如果test1.py使用絕對導(dǎo)入(from Branch import test3),能使用python -m test1運(yùn)行嗎?我試了一下,如果當(dāng)前目錄是testfile就可以。如果在其他目錄下運(yùn)行,比如在testfile所在的目錄(使用python -m testfile.test1運(yùn)行),就不可以。這可能還是與絕對導(dǎo)入相關(guān)。
(許多大型項(xiàng)目,其運(yùn)行入口文件有很多的相對導(dǎo)入,運(yùn)行命令都是帶了-m參數(shù)的。)
【其他用法】
理解import的難點(diǎn)差不多就這樣了。下面說一說import的其他簡單但實(shí)用的用法。
as 改module_name名
import moudle_name as alias
有些module_name比較長,之后寫它時(shí)較為麻煩,或者module_name會出現(xiàn)名字沖突,可以用as來給它改名,如import numpy as np。
只使用模塊中的某些內(nèi)容
from module_name import function_name, variable_name, class_name。
上面導(dǎo)入的都是整個(gè)模塊,有時(shí)候我們只想使用模塊中的某些函數(shù)、某些變量、某些類,用這種寫法就可以了。使用逗號可以導(dǎo)入模塊中的多個(gè)元素。
導(dǎo)入元素過多
有時(shí)候?qū)氲脑睾芏?#xff0c;可以使用反斜杠來換行,官方推薦使用括號。
from Tkinter import Tk, Frame, Button, Entry, Canvas, Text,
LEFT, DISABLED, NORMAL, RIDGE, END # 反斜杠換行
from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
LEFT, DISABLED, NORMAL, RIDGE, END) # 括號換行(推薦)
說到這感覺import的核心已經(jīng)說完了。再跟著上面的博客說一說使用import可能碰到的問題吧。
問題1描述:ValueError: attempted relative import beyond top-level package。直面問題的第一步是去了解熟悉它,最好是能復(fù)現(xiàn)它,讓它躺在兩跨之間任我們?nèi)ホ`踏蹂躪。仍然是上面四個(gè)文件,稍作修改,四個(gè)文件如下:
# test1.py from Branch import test3 test3.printSelf() # test2.py def printSelf():print('I'm test2') # test3.py from .. import test2 # 復(fù)現(xiàn)的關(guān)鍵在這 # print(__name__) def printSelf():print('I'm test3') # test4.py def printSelf():print('I'm test4')運(yùn)行python m1.py,就會出現(xiàn)該問題。問題何在?我猜測,運(yùn)行m1.py后,m1代表的模塊就是頂層模塊(參見上面PEP 328的引用),而m3.py中嘗試導(dǎo)入的m2模塊所在的包(即testfile目錄代表的包)比m1的層級更高,所以會報(bào)出這樣的錯(cuò)誤。怎么解決呢?將m1.py的所有導(dǎo)入改為相對導(dǎo)入,然后進(jìn)入m1.py的上層目錄,運(yùn)行python -m testfile.m1即可。
總結(jié)
以上是生活随笔為你收集整理的python学习之路之:import(详细介绍import的各种调用原理和使用方法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: USB大容量存储设备无法启动--这个设备
- 下一篇: Python中列表,元组,字典的一些基本