python學習日記(模組匯入)
什麼是模組?
常見的場景:一個模組就是一個包含了python定義和宣告的檔案,檔名就是模組名字加上.py的字尾。
但其實import載入的模組分為四個通用類別:
1 使用python編寫的程式碼(.py檔案)
2 已被編譯為共享庫或DLL的C或C++擴充套件
3 包好一組模組的包
4 使用C編寫並連結到python直譯器的內建模組
為何要使用模組?
如果你退出python直譯器然後重新進入,那麼你之前定義的函式或者變數都將丟失,因此我們通常將程式寫到檔案中以便永久儲存下來,需要時就通過python test.py方式去執行,此時test.py被稱為指令碼script。
隨著程式的發展,功能越來越多,為了方便管理,我們通常將程式分成一個個的檔案,這樣做程式的結構更清晰,方便管理。這時我們不僅僅可以把這些檔案當做指令碼去執行,還可以把他們當做模組來匯入到其他的模組中,實現了功能的重複利用。
如何使用模組?
import
示例檔案:自定義模組my_module.py,檔名my_module.py,模組名my_module
print('from my_module.py') x = 100 def read1(): print('my_module->read1->x',x) def read2():print('my_module->read2->x',x) read1() def change(): global x x = 0
重複匯入的問題
模組可以包含可執行的語句和函式的定義,這些語句的目的是初始化模組,它們只在模組名第一次遇到匯入import語句時才執行(import語句是可以在程式中的任意位置使用的,且針對同一個模組很import多次,為了防止你重複匯入,python的優化手段是:第一次匯入後就將模組名載入到記憶體了,後續的import語句僅是對已經載入大記憶體中的模組物件增加了一次引用,不會重新執行模組內的語句),如下
import my_module import my_module import my_module
我們可以從sys.modules中找到當前已經載入的模組,sys.modules是一個字典,內部包含模組名與模組物件的對映,該字典決定了匯入模組時是否需要重新匯入。
import my_module import sys print(sys.modules)
模組與本地的變數衝突問題
每個模組都是一個獨立的名稱空間,定義在這個模組中的函式,把這個模組的名稱空間當做全域性名稱空間,這樣我們在編寫自己的模組時,就不用擔心我們定義在自己模組中全域性變數會在被匯入時,與使用者的全域性變數衝突啦
一、x與my_module.x不衝突
import my_module x = 50 print(my_module.x)
二、read1與my_module.read1不衝突
import my_module def read1(): print('local_test_read1') my_module.read1()
三、執行my_module.change()操作的全域性變數x仍然是my_module中的
import my_module x = 50 my_module.change() print(x) print(my_module.x)
總結
總結:首次匯入模組my_module時會做三件事:
1.為原始檔(my_module模組)建立新的名稱空間,在my_module中定義的函式和方法若是使用到了global時訪問的就是這個名稱空間。
2.在新建立的名稱空間中執行模組中包含的程式碼,見初始匯入import my_module
1 提示:匯入模組時到底執行了什麼? 2 3 In fact function definitions are also ‘statements’ that are ‘executed’; the execution of a module-level function definition enters the function name in the module’s global symbol table. 4 事實上函式定義也是“被執行”的語句,模組級別函式定義的執行將函式名放入模組全域性名稱空間表,用globals()可以檢視匯入模組時到底執行了什麼?
3.建立名字my_module來引用該名稱空間
1 這個名字和變數名沒什麼區別,都是‘第一類的’,且使用my_module.名字的方式可以訪問my_module.py檔案中定義的名字,my_module.名字與test.py中的名字來自兩個完全不同的地方。
模組別名
為模組起別名,相當於a = 1,b = a
import my_module as m print(m.x)
示範用法一:
有兩中sql模組mysql和oracle,根據使用者的輸入,選擇不同的sql功能
#分別建立兩個資料庫模組 #mysql.py def sqlparse(): print('from mysql slparse') #oracle.py def sqlparse(): print('from oracle sqlparse')
db_type = input('please input db_name:') if db_type.strip().lower() == 'mysql': import mysql as db elif db_type.strip().lower() == 'oracle': import oracle as sb db.sqlparse()
示範用法二:
為已經匯入的模組起別名的方式對編寫可擴充套件的程式碼很有用,假設有兩個模組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 os,sys,re
from...import...
簡述
Python 的 from 語句讓你從模組中匯入一個指定的部分到當前名稱空間中,語法如下:
from modname import name1[, name2[, ... nameN]]
例如,要匯入模組 modname 的 name1 函式,使用如下語句:
from modname import name1
這個宣告不會把整個modname模組匯入到當前的名稱空間中,它只會將modname裡的name1函式引入進來。
#測試一:匯入的函式read1,執行時仍然回到my_module.py中尋找全域性變數 x from my_module import read1 x = 0.1 read1() print('分割線'.center(20,'-')) #測試二:匯入的函式read2,執行時需要呼叫read1(),仍然回到my_module.py中找read1() from my_module import read2 def read1(): print('11111111') read2()
覆蓋情況
匯入的函式read1,被當前位置定義的read1覆蓋掉了
from my_module import read1 def read1(): print('1111111111') read1()
注意:繫結關係
需要特別強調的一點是:python中的變數賦值不是一種儲存操作,而只是一種繫結關係,如下:
from my_module import x,read1 x = 0.1#將當前位置的名字x繫結到了100 print(x)#列印當前的名字 read1()#讀取my_module.py中的名字x,仍然為100
也可重新命名
from my_module import read1 as r r()
也可匯入多行
from my_module import (x, read1, read2)
from … import *
簡述
from my_module import * 把my_module中所有的不是以下劃線(_)開頭的名字都匯入到當前位置,大部分情況下我們的python程式不應該使用這種匯入方式,因為*你不知道你匯入什麼名字,很有可能會覆蓋掉你之前已經定義的名字。而且可讀性極其的差,在互動式環境中匯入時沒有問題。
這種宣告不該被過多地使用。
from my_module import * print(x) print(read1) print(read2) print(change)
__all__
如果沒有這個變數,就會匯入模組中所有的名字
如果有這個變數,就只匯入__all__列表中的名字
__all__ = ['read1']#這樣在另外一個檔案中用from my_module import *就這能匯入列表中規定的一個名字
__name__
一個模組被另一個程式第一次引入時,其主程式將執行。如果我們想在模組被引入時,模組中的某一程式塊不執行,我們可以用__name__屬性來使該程式塊僅在該模組自身執行時執行。
說明: 每個模組都有一個__name__屬性,當其值是'__main__'時,表明該模組自身在執行,否則是被引入。
說明:__name__ 與 __main__ 底下是雙下劃線, _ _ 是這樣去掉中間的那個空格。
import my_module as m if m.__name__ == '__main__': print('程式自身在執行') else: print('我來自另一個模組') print('分割線'.center(15,'-')) #自身 if __name__ == '__main__': print('程式自身在執行') else: print('我來自另一個模組')
pass