Python 模塊(Module),是一個 Python 文件,以 .py 結尾,包含了 Python 對象定義和Python語句。python
模塊讓你可以有邏輯地組織你的 Python 代碼段。mysql
把相關的代碼分配到一個模塊裏能讓你的代碼更好用,更易懂。 sql
模塊能定義函數,類和變量,模塊裏也能包含可執行的代碼。windows
包括:內置模塊,自定義模塊,第三方模塊;api
最大的好處是大大提升了代碼的可維護性。其次,編寫代碼沒必要從零開始。當一個模塊編寫完畢,就能夠被其餘地方引用。咱們在編寫程序的時候,也常常引用其餘模塊,包括Python內置的模塊和來自第三方的模塊。app
使用模塊還能夠避免函數名和變量名衝突。相同名字的函數和變量徹底能夠分別存在不一樣的模塊中,所以,咱們本身在編寫模塊時,沒必要考慮名字會與其餘模塊衝突。可是也要注意,儘可能不要與內置函數名字衝突。函數
模塊定義好後,咱們可使用 import 語句來引入模塊,語法以下:測試
import module1[, module2[,... moduleN]
例:優化
#spam.py print('from the spam.py') money=1000 def read1(): print('spam->read1->money',money) def read2(): print('spam->read2 calling read') read1() def change(): global money money=0
導入模塊spa
import spam #只在第一次導入時才執行spam.py內代碼,此處的顯式效果是隻打印一次'from the spam.py',固然其餘的頂級代碼也都被執行了,只不過沒有顯示效果. 執行結果: from the spam.py
注:模塊能夠包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第一次遇到導入import語句時才執行(import語句是能夠在程序中的任意位置使用的,且針對同一個模塊很import屢次,爲了防止你重複導入,python的優化手段是:第一次導入後就將模塊名加載到內存了,後續的import語句僅是對已經加載大內存中的模塊對象增長了一次引用,不會從新執行模塊內的語句)
import導入模塊乾的事:
1.產生新的名稱空間
2.以新建的名稱空間爲全局名稱空間,執行文件的代碼
3.拿到一個模塊名spam,指向spam.py產生的名稱空間
測試一:money與spam.money不衝突
#測試一:money與spam.money不衝突 #test.py import spam money=10 print(spam.money) ''' 執行結果: from the spam.py 1000 '''
測試二:read1與spam.read1不衝突
#測試二:read1與spam.read1不衝突 #test.py import spam def read1(): print('========') spam.read1() ''' 執行結果: from the spam.py spam->read1->money 1000 '''
測試三:執行spam.change()操做的全局變量money仍然是spam中的money
#測試三:執行spam.change()操做的全局變量money仍然是spam中的 #test.py import spam money=1 spam.change() print(money) ''' 執行結果: from the spam.py 1 '''
as,爲模塊名起別名
import spam as sm #sm爲spam的別名 print(sm.money)
例:
爲已經導入的模塊起別名的方式對編寫可擴展的代碼頗有用,假設有兩個模塊xmlreader.py和csvreader.py,它們都定義了函數read_data(filename):用來從文件中讀取一些數據,但採用不一樣的輸入格式。能夠編寫代碼來選擇性地挑選讀取模塊,例如
if file_format == 'xml': import xmlreader as reader elif file_format == 'csv': import csvreader as reader data=reader.read_date(filename)
在一行導入多個模塊
import sys,os,re
from modname import name1[, name2[, ... nameN]]
要導入模塊 fib 的 fibonacci 函數,使用以下語句:
from fib import fibonacci
這個聲明不會把整個 fib 模塊導入到當前的命名空間中,它只會將 fib 裏的 fibonacci 單個引入到執行這個聲明的模塊的全局符號表。
from... import..導入模塊乾的事:
1.產生新的名稱空間
2.以新建的名稱空間爲全局名稱空間,執行文件的代碼
3.直接拿到就是spam.py產生的名稱空間中名字
#測試一:導入的函數read1,執行時仍然回到spam.py中尋找全局變量money #test.py from spam import read1 money=1000 read1() ''' 執行結果: from the spam.py spam->read1->money 1000 ''' #測試二:導入的函數read2,執行時須要調用read1(),仍然回到spam.py中找read1() #test.py from spam import read2 def read1(): print('==========') read2() ''' 執行結果: from the spam.py spam->read2 calling read spam->read1->money 1000 '''
但若是當前有重名read1或者read2,那麼會有覆蓋效果。
#測試三:導入的函數read1,被當前位置定義的read1覆蓋掉了 #test.py from spam import read1 def read1(): print('==========') read1() ''' 執行結果: from the spam.py ========== '''
須要特別強調的一點是:python中的變量賦值不是一種存儲操做,而只是一種綁定關係,以下:
from spam import money,read1 money=100 #將當前位置的名字money綁定到了100 print(money) #打印當前的名字 read1() #讀取spam.py中的名字money,仍然爲1000 ''' from the spam.py 100 spam->read1->money 1000 '''
from ... import ...
優勢:方便,不用加前綴
缺點:容易跟當前文件的名稱空間衝突
from ... import...也支持as和導入多模塊
from spam import read1 as read from spam import (read1, read2, money)
from spam import *
把spam中全部的不是如下劃線(_)開頭的名字都導入到當前位置,大部分狀況下咱們的python程序不該該使用這種導入方式,由於*你不知道你導入什麼名字,頗有可能會覆蓋掉你以前已經定義的名字。並且可讀性極其的差,在交互式環境中導入時沒有問題。
from spam import * #將模塊spam中全部的名字都導入到當前名稱空間 print(money) print(read1) print(read2) print(change) ''' 執行結果: from the spam.py 1000 <function read1 at 0x1012e8158> <function read2 at 0x1012e81e0> <function change at 0x1012e8268> '''
__all__來控制*(用來發布新版本)
在spam.py中新增一行
__all__=['money','read1'] #這樣在另一個文件中用from spam import *就這能導入列表中規定的兩個名字
name
spam.py當作腳本執行,__name__='__main__'
spam.py當作模塊導入,__name__=模塊名
做用:用來控制.py文件在不一樣的應用場景下執行不一樣的邏輯
#fib.py def fib(n): # write Fibonacci series up to n a, b = 0, 1 while b < n: print(b, end=' ') a, b = b, a+b print() def fib2(n): # return Fibonacci series up to n result = [] a, b = 0, 1 while b < n: result.append(b) a, b = b, a+b return result if __name__ == "__main__": import sys fib(int(sys.argv[1]))
執行
#python fib.py <arguments> python fib.py 50 #在命令行
模塊的查找順序是:內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊
python解釋器在啓動時會自動加載一些模塊,可使用sys.modules查看,在第一次導入某個模塊時(好比spam),會先檢查該模塊是否已經被加載到內存中(當前執行文件的名稱空間對應的內存),若是有則直接引用
若是沒有,解釋器則會查找同名的內建模塊,若是尚未找到就從sys.path給出的目錄列表中依次尋找spam.py文件。
特別注意的是:自定義的模塊名不該該與系統內置模塊重名。
在初始化後,python程序能夠修改sys.path,路徑放到前面的優先於標準庫被加載。
注意:搜索時按照sys.path中從左到右的順序查找,位於前的優先被查找,sys.path中還可能包含.zip歸檔文件和.egg文件,python會把.zip歸檔文件當成一個目錄去處理,
#首先製做歸檔文件:zip module.zip foo.py bar.py import sys sys.path.append('module.zip') import foo,bar #也可使用zip中目錄結構的具體位置 sys.path.append('module.zip/lib/python')
注意:windows下的路徑不加r開頭,會語法錯誤
windows下的路徑不加r開頭,會語法錯誤 sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\a')
包是一種經過使用‘.模塊名’來組織python模塊名稱空間的方式。
不管是import形式仍是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提升警覺:這是關於包纔有的導入語法。.的左邊必須是包;
包是一個分層次的文件目錄結構,它定義了一個由模塊及子包,和子包下的子包等組成的 Python 的應用環境。簡單來講,包就是文件夾,但該文件夾下必須存在 __init__.py 文件, 該文件的內容能夠爲空。__int__.py用於標識當前文件夾是一個包。
包是由一系列模塊組成的集合。模塊是處理某一類問題的函數和類的集合。
例:
glance/ #Top-level package ├── __init__.py #Initialize the glance package ├── api #Subpackage for api │ ├── __init__.py │ ├── policy.py │ └── versions.py ├── cmd #Subpackage for cmd │ ├── __init__.py │ └── manage.py └── db #Subpackage for db ├── __init__.py └── models.py
文件內容
#文件內容 #policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py') #models.py def register_models(engine): print('from models.py: ',engine)
在使用一個模塊中的函數或類以前,首先要導入該模塊。模塊的導入使用import語句。
調用模塊的函數或類時,須要以模塊名做爲前綴。
import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字一樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
例:
在與包glance同級別的文件中測試
import glance.db.models glance.db.models.register_models('mysql')
凡是在導入時帶點的,點的左邊都必須是一個包。
若是不想在程序中使用前綴符,可使用from…import…語句將模塊導入。
須要注意的是from後import導入的模塊,必須是明確的一個不能帶點,不然會有語法錯誤,如:from a import b.c是錯誤語法
例:
在與包glance同級別的文件中測試
from glance.db import models models.register_models('mysql') from glance.db.models import register_models register_models('mysql')
執行的文件的當前路徑就是sys.path
import sys print(sys.path)
注意:
1.關於包相關的導入語句也分爲import和from ... import ...兩種,可是不管哪一種,不管在什麼位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,不然非法。能夠帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。
2.對於導入後,在使用時就沒有這種限制了,點的左邊能夠是包,模塊,函數,類(它們均可以用點的方式調用本身的屬性)。
3.對比import item 和from item import name的應用場景:
若是咱們想直接使用name那必須使用後者。
不論是哪一種方式,只要是第一次導入包或者是包的任何其餘部分,都會依次執行包下的__init__.py文件(咱們能夠在每一個包的文件內都打印一行內容來驗證一下),這個文件能夠爲空,可是也能夠存放一些初始化包的代碼。
從包api中導入全部,實際上該語句只會導入包api下__init__.py文件中定義的名字,咱們能夠在這個文件中定義__all___:
#在__init__.py中定義 x=10 def func(): print('from api.__init.py') __all__=['x','func','policy']
此時咱們在於glance同級的文件中執行from glance.api import *就導入__all__中的內容(versions仍然不能導入)。
最頂級包glance是寫給別人用的,而後在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:
絕對導入:以glance做爲起始
相對導入:用.或者..的方式最爲起始(只能在一個包中使用,不能用於不一樣目錄內)
例:咱們在glance/api/version.py中想要導入glance/cmd/manage.py
在glance/api/version.py #絕對導入 from glance.cmd import manage manage.main() #相對導入 from ..cmd import manage manage.main()
測試結果:注意必定要在於glance同級的文件中測試
from glance.api import versions
注意:能夠用import導入內置或者第三方模塊(已經在sys.path中),可是要絕對避免使用import來導入自定義包的子模塊(沒有在sys.path中),應該使用from... import ...的絕對或者相對導入,且包的相對導入只能用from的形式。
單獨導入包名稱時不會導入包中全部包含的全部子模塊,如
#在與glance同級的test.py中 import glance glance.cmd.manage.main() ''' 執行結果: AttributeError: module 'glance' has no attribute 'cmd' '''
解決方法:
#glance/__init__.py from . import cmd #glance/cmd/__init__.py from . import manage
執行:
#在於glance同級的test.py中 import glance glance.cmd.manage.main()
千萬別問:__all__不能解決嗎,__all__是用於控制from...import *