1、子產品導入方法
常見的場景:
一個子產品就是一個包含了python定義和聲明的檔案,檔案名就是子產品名字加上.py的字尾,導入子產品可以實作功能的重複利用
import加載的子產品分為四個通用類别:
1 使用python編寫的代碼(.py檔案)
2 已被編譯為共享庫或DLL的C或C++擴充
3 包好一組子產品的包
4 使用C編寫并連結到python解釋器的内置子產品
a. import語句
python 内置了很多子產品,比如os、sys、time等,也可以是自定義子產品、子產品包、C擴充等,使用import無法區分導入的子產品類型
import 子產品名
例如:導入spam.py
import spam(不含.py)
導入多個子產品:
import os,time,sys
子產品可以包含可執行的語句和函數的定義,這些語句的目的是初始化子產品,它們隻在子產品名第一次遇到導入import語句時才執行(import語句是可以在程式中的任意位置使用的,且針對同一個子產品import很多次,為了防止你重複導入,python的優化手段是:第一次導入後就将子產品名加載到記憶體了,後續的import語句僅是對已經加載大記憶體中的子產品對象增加了一次引用,不會重新執行子產品内的語句)
每個子產品都是一個獨立的名稱空間,定義在這個子產品中的函數,把這個子產品的名稱空間當做全局名稱空間,這樣我們在編寫自己的子產品時,就不用擔心我們定義在自己子產品中全局變量會在被導入時,與使用者的全局變量沖突
導入子產品幹了哪些事:
1 執行源檔案
2 以一個源檔案的全局名稱空間
3 在目前位置拿到一個子產品名,指向2建立的名稱空間
<code>#測試一:money與spam.money不沖突</code>
<code>#test.py</code>
<code>import</code> <code>spam</code>
<code>money</code><code>=</code><code>10</code>
<code>print</code><code>(spam.money)</code>
<code>輸出:</code>
<code>from</code> <code>the spam.py</code>
<code>1000</code>
<code> </code>
<code>#測試二:read1與spam.read1不沖突</code>
<code>def</code> <code>read1():</code>
<code> </code><code>print</code><code>(</code><code>'========'</code><code>)</code>
<code>spam.read1()</code>
<code>輸出:</code>
<code>spam</code><code>-</code><code>>read1</code><code>-</code><code>>money1000</code>
<code>#測試三:執行spam.change()操作的全局變量money仍然是spam中的</code>
<code>money</code><code>=</code><code>1</code>
<code>spam.change()</code>
<code>print</code><code>(money)</code>
<code>1</code>
子產品别名功能
練習:
有兩鐘sql子產品mysql和oracle,根據使用者的輸入,選擇不同的sql功能
<code>#mysql.py</code>
<code>def</code> <code>sqlparse():</code>
<code> </code><code>print</code><code>(</code><code>'from mysql sqlparse'</code><code>)</code>
<code>#oracle.py</code>
<code> </code><code>print</code><code>(</code><code>'from oracle sqlparse'</code><code>)</code>
<code>db_type</code><code>=</code><code>input</code><code>(</code><code>'>>: '</code><code>)</code>
<code>if</code> <code>db_type </code><code>=</code><code>=</code> <code>'mysql'</code><code>:</code>
<code> </code><code>import</code> <code>mysql as db</code>
<code>elif</code> <code>db_type </code><code>=</code><code>=</code> <code>'oracle'</code><code>:</code>
<code> </code><code>import</code> <code>oracle as db</code>
<code>db.sqlparse()</code>
為已經導入的子產品起别名的方式對編寫可擴充的代碼很有用,假設有兩個子產品xmlreader.py和csvreader.py,它們都定義了函數read_data(filename):用來從檔案中讀取一些資料,但采用不同的輸入格式。可以編寫代碼來選擇性地挑選讀取子產品
<code>if</code> <code>file_format </code><code>=</code><code>=</code> <code>'xml'</code><code>:</code>
<code> </code><code>import</code> <code>xmlreader asreader</code>
<code>elif</code> <code>file_format </code><code>=</code><code>=</code> <code>'csv'</code><code>:</code>
<code> </code><code>import</code> <code>csvreader asreader</code>
<code>data</code><code>=</code><code>reader.read_date(filename)</code>
b. from…import語句
from 子產品名 import 子產品名中的方法
例如:from spamimport money,read1,read2,change
如果子產品中的方法太多,可以使用:
from spam import * (不推薦使用,容易與執行檔案的命名空間沖突)
__all__=['money','x'] #對from spam import * 有用,之後導入money、x方法
_money=1000 #對from spam import * 有用,不會導入這個方法
對比import spam,會将源檔案的名稱空間'spam'帶到目前名稱空間中,使用時必須是spam.名字的方式,而from 語句相當于import,也會建立新的名稱空間,但是将spam中的名字直接導入到目前的名稱空間中,在目前名稱空間中,直接使用名字就可以了
<code>#spam.py</code>
<code>print</code><code>(</code><code>'from the spam.py'</code><code>)</code>
<code>money</code><code>=</code><code>0</code>
<code> </code><code>print</code><code>(</code><code>'spam->read1->money'</code><code>,money)</code>
<code>def</code> <code>read2():</code>
<code> </code><code>print</code><code>(</code><code>'spam->read2 calling read'</code><code>)</code>
<code> </code><code>read1()</code>
<code>def</code> <code>change():</code>
<code> </code><code>global</code> <code>money</code>
<code> </code><code>money</code><code>=</code><code>0</code>
<code># 執行檔案</code>
<code>from</code> <code>spam </code><code>import</code> <code>money,read1,read2,change</code>
<code>print</code><code>(read1)</code>
<code>from</code> <code>the spam.py </code><code>#首先執行spam.py</code>
<code>0</code> <code>#仍然是目前執行檔案的命名空間中的money</code>
<code><function read1 at </code><code>0x00000000026DE950</code><code>></code>
優點:使用源檔案内的名字時無需加字首,使用友善
缺點:容易與目前檔案的名稱空間内的名字混淆
c. 子產品搜尋路徑
子產品隻在第一次導入時才會執行,之後的導入都是直接引用記憶體已經存在的結果
import sys
print('spam' in sys.modules) #存放的是已經加載到内的子產品
注意:自定義的子產品名一定不要與python自帶的子產品名重名
子產品的查找順序是:記憶體中已經加載的子產品->内置子產品->sys.path路徑中包含的子產品
<code>import</code> <code>time</code>
<code>import</code> <code>importlib</code>
<code>import</code> <code>spam </code><code>#導入子產品會把硬碟中的子產品内容加載到記憶體中</code>
<code>time.sleep(</code><code>20</code><code>)</code>
<code>import</code> <code>spam </code><code>#再次導入會直接從記憶體中查找,忽略硬碟中子產品内容</code>
<code>importlib.</code><code>reload</code><code>(spam) </code><code>#會重新加載子產品(隻在測試環境使用)</code>
print(sys.path) #子產品的搜尋路徑
sys.path從以下位置初始化
1 執行檔案所在的目前目錄
2 PTYHONPATH(包含一系列目錄名,與shell變量PATH文法一樣)
3 依賴安裝時預設指定的
加入子產品路徑:
<code>import</code> <code>sys</code>
<code>print</code><code>(sys.path)</code>
<code>sys.path.insert(</code><code>0</code><code>,r</code><code>'要添加的子產品路徑'</code><code>) </code><code>#插入子產品路徑</code>
<code>sys.path.append(r</code><code>'要添加的子產品路徑'</code><code>) </code><code>#追加子產品路徑</code>
d. 區分python檔案的兩種用途
檔案當做腳本(執行檔案)運作時__name__等于__main__
檔案當做子產品被加載運作時__name__等于子產品名
<code># m1.py</code>
<code>import</code> <code>os,sys</code>
<code>x</code><code>=</code><code>1</code>
<code>def</code> <code>func1():</code>
<code> </code><code>print</code><code>(</code><code>'from m1'</code><code>)</code>
<code>def</code> <code>func2():</code>
<code> </code><code>print</code><code>(</code><code>'from m2'</code><code>)</code>
<code>def</code> <code>func3():</code>
<code> </code><code>print</code><code>(</code><code>'from m3'</code><code>)</code>
<code># print(__name__)</code>
<code>#檔案當做腳本運作時__name__等于__main__</code>
<code>#檔案當做子產品被加載運作時__name__等于子產品名</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>
<code> </code><code>#當做腳本使用時才執行</code>
<code> </code><code>func1()</code>
<code> </code><code>func2()</code>
<code> </code><code>func3() </code>
<code># run.py</code>
<code>import</code> <code>m1 </code><code>#導入m1子產品</code>
<code>m1.func3()</code>
e. 包
python3中建立檔案夾會自動建立__init__.py
python2中建立包需要手動建立__init__.py
1. 無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關于包才有的導入文法
2. 包是目錄級的(檔案夾級),檔案夾是用來組成py檔案(包的本質就是一個包含__init__.py檔案的目錄)
3. import導入檔案時,産生名稱空間中的名字來源于檔案,import 包,産生的名稱空間的名字同樣來源于檔案,即包下的__init__.py,導入包本質就是在導入該檔案
強調:
1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯
2. 建立包的目的不是為了運作,而是被導入使用,記住,包隻是子產品的一種形式而已,包即子產品
3.凡是在導入時帶點的,點的左邊都必須是一個包
本文轉自lyndon部落格51CTO部落格,原文連結http://blog.51cto.com/lyndon/1953171如需轉載請自行聯系原作者
遲到的棟子