常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴,但其實import加載的模塊分爲四個通用類別:html
若是你退出Python解釋器而後再進入,那麼你以前定義的函數或變量都將丟失,所以咱們一般將程序寫到文件中以便永久保存下來,須要時就經過python 文件.py ,此時執行的文件就叫作script。當文件腳本不少時,咱們將程序分紅一個個文件,這樣程序的結構就更清晰,方便管理,這時咱們不只僅能夠把這些文件當成腳本文件,還能夠把他們看成模塊來導入到其餘模塊,實現功能的重用node
使用模塊: 咱們能夠從sys.modules中找到當前已經加載的模塊python
模塊的導入至關於執行了整個文件web
一個模塊不能被屢次導入,一旦導入原文件中的修改也不會生效,且各個模塊的變量於本模塊不衝突json
#測試一:money與my_module.money不衝突
import my_module # 默認有如下屬性
money=10
print(my_module.money) #屬性和方法均可以my_moudle.方法()
my_moudle.read()
'''
執行結果:
from the my_module.py
1000
'''
import my_moudle # 次文件中有print('123')
import my_moudle
# 打印一個 123
一個模塊不會被屢次執行,只執行一遍,再兩個模塊相互調用時要分清。:第一次導入後就將模塊名加載到內存了,後續的import語句僅是對已經加載大內存中的模塊對象增長了一次引用,不會從新執行模塊內的語句。windows
導入一個模塊的時候命名空間的變化:api
模塊雖然一行能夠導入多個,可是不推薦這樣使用。如:import time,os,random,my_moduleapp
as語法的使用:less
xxxxxxxxxx
#一、time這個名字就失效的,只剩下t了
import time as t
t.time()
#二、用來作兼容,當要根據判斷取模塊時,咱們能夠先判斷,再以一樣的as名字
mode = 'pickle' #不肯定是 json仍是 pickle
if mode == 'pickle':
import pickle as mode
else:
import json as mode
def dump():
mode.dump(obj,f)
def load():
mode.load(f)
#其餘用法:
#1
from my_module import read1 as read
#2
from my_module import (read1,
read2,
money)
from …… import ……from 語句至關於import,也會建立新的名稱空間,可是將my_module中的名字直接導入到當前的名稱空間中,在當前名稱空間中,直接使用名字就能夠了dom
xxxxxxxxxx
#1測試一:導入的函數read1,執行時仍然回到my_module.py中尋找全局變量money
from my_module import read1
money=1000
read1()
'''
執行結果:
from the my_module.py
spam->read1->money 1000
'''
#測試二:導入的函數read2,執行時須要調用read1(),仍然回到my_module.py中找read1()
from my_module import read2
def read1():
print('==========')
read2()
'''
執行結果:
from the my_module.py
my_module->read2 calling read1
my_module->read1->money 1000
'''
#測試三:導入的函數read1,被當前位置定義的read1覆蓋掉了
from my_module import read1
def read1():
print('==========')
read1()
'''
執行結果:
from the my_module.py
==========
'''
#from my_module import * 把my_module中全部的不是如下劃線(_)開頭的名字都導入到當前位置,大部分狀況下咱們的python程序不該該使用這種導入方式,由於*你不知道你導入什麼名字,頗有可能會覆蓋掉你以前已經定義的名字。並且可讀性極其的差,在交互式環境中導入時沒有問題
#在my_module.py中新增一行:
__all__=['money','read1']
#這樣在另一個文件中用from my_module import *就這能導入列表中規定的兩個名字
#__all__=[] 和 * 配合使用
#補充:
#若是my_module.py中的名字前加_,即_money,則from my_module import *,則_money不能被導入
模塊的搜索路徑:
python解釋器在啓動時會自動加載一些模塊,可使用sys.modules查看,在第一次導入某個模塊時(好比my_module),會先檢查該模塊是否已經被加載到內存中(當前執行文件的名稱空間對應的內存),若是有則直接引用.若是沒有,解釋器則會查找同名的內建模塊,若是尚未找到就從sys.path給出的目錄列表中依次尋找my_module.py文件。
xxxxxxxxxx
#一、因此總結模塊的查找順序是:內存中已經加載的模塊 -> 內置模塊 -> ys.path路徑中包含的模塊
#二、須要特別注意的是:咱們自定義的模塊名不該該與系統內置模塊重名
#三、搜索時按照sys.path中從左到右的順序查找,位於前的優先被查找,sys.path中還可能包含.zip歸檔文件和.egg文件,python會把.zip歸檔文件當成一個目錄去處理。在pycharm中會自動爲咱們加載本地路徑
import sys
sys.path.append('/a/b/c/d')
sys.path.insert(0,'/x/y/z') #排在前的目錄,優先被搜索
模塊能不能被循環導入:
xxxxxxxxxx
#能不能 在 a.py import b
#在 b.py import a
# 以主程序爲主,加載順序從上至下,可引用
把模塊當作腳本執行:
當作腳本運行:__name__ 等於'__main__'
:__name__
等於模塊名
xxxxxxxxxx
def fib(n):
a, b = 0, 1
while b < n:
print(b, end=' ')
a, b = b, a+b
print()
if __name__ == "__main__": #只有在當前文件下執行,若是是模塊調用則不會執行
print(__name__)
num = input('num :')
fib(int(num))
包是一種經過使用'模塊名'來組織python模塊名稱空間的方式。
不管是import形式仍是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提升警覺:這是關於包纔有的導入語法
包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是一個包含__init__.py
文件的目錄
import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字一樣來源於文件,即包下的__init__.py
,導入包本質就是在導入該文件
在python3中,即便包下沒有__init__.py
文件,import 包仍然不會報錯,而在python2中,包下必定要有該文件,不然import 包報錯
建立包的目的不是爲了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包即模塊
import 包:至關於執行了這個包下的init文件
具體使用:
xxxxxxxxxx
import glance.api.policy as policy #假設glance是包,api是文件,policy是py文件 用別名
policy.get()
#也能夠:import glance.api.policy.get() 可是太長了,每一個都要寫
# 根據包的導入要精確到模塊名,不能精確到具體的函數或者變量,而後使用glance.api.policy或者重命名的方式,來使用這個模塊中的全部名字
#from……import 在包中的用法
from glance.api import policy #import後面不能有. 且至少要精確到模塊
policy.get()
#or
from glance.api.policy import get
get()
#使用from……import import後面至少是精確到模塊的,import後面不能有。from後面能夠有.,可是.的左邊永遠是包名
#import 直接導入包時,再導入時執行了包中的__init__.py文件(相似於實例化),咱們能夠在__init__.py中寫相應的路由,假如我想直接import 一個包,就須要配置__init__.py文件:
# 一、如今glance(包)中的__init__.py,須要配置:
__init__.py
文件:不論是哪一種方式,只要是第一次導入包或者是包的任何其餘部分,都會依次執行包下的init.py文件(咱們能夠在每一個包的文件內都打印一行內容來驗證一下),這個文件能夠爲空,可是也能夠存放一些初始化包的代碼
首先要想使用import glance 裏面的如api下的policy中的方法,先配置glance文件下的__init__.py
xxxxxxxxxx
# /glance/__init__.py
from glance import api
from glance import cmd
from glance import db # 此時在包外一個文件import glance,能夠調用api,cmd,db,可是還不能導入其中的具體方法
#test/my_moudle
import glance
print(glance) # <moudle 'glance' from 'D:\\'>
print(glance.api) #<moudle 'glance.api' from 'D:……>
print(glance.api.policy) #不行 如何解決,由於沒有在api文件的init中配置路徑
#此時在api/__init__.py中輸入
from api import policy # 以後再運行仍是報錯,問題出在from api這裏,找不到api,這時候能夠經過sys.path 查看路徑,顯示只能查看能找到glance,也就是說能執行glance中的__init__.py文件,可是不能執行api中的init文件,因此這裏有兩種方法解決這個問題:
#方案一: 在api文件中的__init.py文件中添加路徑
import sys
sys.path.append(r'D:\……\glance') #將glace文件加載到系統路徑中,因而會查找其中的各個文件
from api import policy # 導入glance後,api文件就會被找到,一層一層的
from api import versions
#此時api文件下的文件均可以使用了,可是若是要導入cmd文件下的文件,就還須要在它文件下的init文件作一樣的處理。麻煩
#方案二:絕對路徑,不須要添加路經,使用絕對導入、
#/glance/api/__init__.py
from glance.api import policy #效果相同,不須要讓api的上一級成爲環境變量中
from glance.api import versions
#總結: 在包中的__init__.py文件中的就是在import時要執行的文件,各級子文件的__init__.py文件最好使用絕對導入,這樣,想導入的時候才能找到
絕對導入:以glance做爲起始
相對導入:用.或者..的方式最爲起始(只能在一個包中使用,不能用於不一樣目錄內)
xxxxxxxxxx
#在glance/api/version.py
#絕對導入
from glance.cmd import manage
manage.main()
#相對導入
from ..cmd import manage
manage.main()
#能夠用import導入內置或者第三方模塊(已經在sys.path中),可是要絕對避免使用import來導入自定義包的子模塊(沒有在sys.path中),應該使用from... import ...的絕對或者相對導入,且包的相對導入只能用from的形式。
單獨導入包:單獨導入包名稱時不會導入包中全部包含的全部子模塊
x
#在與glance同級的test.py中
import glance
glance.cmd.manage.main()
'''
執行結果:
AttributeError: module 'glance' has no attribute 'cmd'
'''
#解決辦法: 規劃路經,使用__init__.py,__all__是用於控制from...import *
#glance/__init__.py
from . import cmd
#glance/cmd/__init__.py
from . import manage
#執行
#在於glance同級的test.py中
import glance
glance.cmd.manage.main()
x
# 同一大文件下(項目目錄),如何導入各個小文件中的py文件的導入: __file__:當前文件路徑
#項目開始的文件中導入
import os
start_path = __file__
bin_path = os.path.dirname(start_path) # 翻一層
project_path = os.path.dirname(bin_path) # 再翻
sys.path.append(project_path) # 添加路徑,能夠遷移文件
#規定
Base_path = os.path.dirname(os.path.dirname(__file__))
sys.path.append(project_path)
#注意的是:在每一個模塊的開頭,須要導入時,都須要使用from 父目錄 import ……,也就是說如今項目的全部小目錄能找到,因此,咱們的子目錄都是要記錄這些小目錄開始 from。